2009-12-09 24 views
8

Tôi đã bắt đầu với .NET CLR một lúc và ngôn ngữ tôi chọn là C#.Các tình huống hoặc ưu và nhược điểm khi sử dụng C++/CLI trên C#

Cho đến gần đây, tôi không biết rằng C++/CLI có thể tạo các tệp thi hành "chế độ hỗn hợp" có khả năng chạy mã gốc và được quản lý.

Bây giờ biết điều này, một người bạn phát triển khác của tôi đang thảo luận thuộc tính này và cố gắng xác định khi nào và làm thế nào khả năng này sẽ hữu ích.

Tôi coi đó là mã nguồn gốc có khả năng hiệu quả và mạnh mẽ hơn mã được quản lý, với chi phí cho thời gian phát triển bổ sung.

Trước đây, tôi đã sử dụng đúng các thư viện mã C++ gốc và sử dụng Interop để sử dụng chức năng tôi đã viết vào thư viện gốc.

Tôi có thể thấy lợi ích của việc không yêu cầu thư viện bổ sung, nhưng tôi tò mò muốn biết tất cả ưu điểm/nhược điểm của việc sử dụng C++/CLI trên bản thực thi được quản lý bằng C#, hoặc thực thi bằng Interop để gọi một thư viện thuần túy C++?

(Phụ chú:. Có những điều khoản Interop/PInvoke hoán đổi cho nhau, như tôi d.on't hiểu sự khác biệt giữa các điều khoản, chỉ cần nhìn thấy chúng sử dụng cùng một cách)

Trả lời

13

Với C++/CLI bạn có thể tạo, nói chung, ba loại đối tượng:

  1. Loại được quản lý. Chúng sẽ biên dịch về cơ bản cùng một IL như C# tương đương. Không có cơ hội biểu diễn ở đây.
  2. Loại gốc. Biên dịch xuống mã gốc như thể bạn đã sử dụng thẳng C++.
  3. Loại chế độ hỗn hợp. Các mã này được biên dịch thành mã được quản lý, nhưng cũng cho phép bạn tham chiếu đến các kiểu gốc.

Bạn có thể nghĩ (3) giống như viết mã C# với mã PInvoke để truy cập nội dung gốc - ngoại trừ tất cả nội dung PInvoke được tạo cho bạn.

Có nhiều điều hơn thế, tất nhiên, cũng như một số thông báo - nhưng điều đó sẽ cung cấp cho bạn ý tưởng về cách nó hữu ích.

Nói cách khác, đó thực sự là ngôn ngữ dán. Trong khi bạn có thể viết các ứng dụng đầy đủ trong C++/CLI thì việc giữ cho các phần được quản lý và riêng biệt trở nên bình thường và sử dụng C++/CLI để kết nối hai ứng dụng một cách rõ ràng hơn với PInvoke.

Một cách sử dụng phổ biến khác là mở rộng và tồn tại, cơ sở mã C++ gốc, hiện có với các cuộc gọi thư viện .Net.

Hãy cẩn thận khi bạn phân đoạn mã của mình tốt vì đôi khi có thể khá tinh tế khi biên dịch mã C++ thuần túy xuống IL một cách minh bạch!

Như bên lề của bạn: PInvoke là một loại Interop cụ thể. Interop cũng có các dạng khác, chẳng hạn như COM Interop. Trong thực tế, chính xác hơn, PInvoke là một tập hợp các tính năng ngôn ngữ làm cho Interop với mã gốc dễ dàng hơn.

+2

+1 để gọi nó là ngôn ngữ keo. Mô tả hay nhất về C++/CLI. – Randolpho

+0

có, và khói có thể độc hại như nhau ;-) – philsquared

+0

Ồ, tôi không biết về điều đó. Tôi thực sự thích nó. – Randolpho

3

Tôi đã sử dụng Managed C++ (tiền tố .NET 1.1 cho C++/CLI) một cách hiệu quả trong quá khứ. Tôi thấy nó hoạt động tốt nhất khi bạn có một thư viện C hoặc C++ bản địa mà bạn muốn sử dụng trong mã được quản lý.Bạn có thể đi toàn bộ Interop/PInvoke tuyến đường, mà làm cho một số mã C# xấu xí và thường xuyên có vấn đề marshalling, hoặc bạn có thể viết một C++ wrapper quản lý, đó là nơi C + +/CLI thực sự tỏa sáng.

Bởi vì C++/CLI được quản lý mã, bạn có thể gọi nó từ C# (hoặc VB.NET nếu bạn nghiêng theo cách đó) theo cách thông thường, bằng cách thêm tham chiếu đến .DLL. Không marshalling, không dllimport, không có gì ngốc nghếch như thế. Chỉ cần tham khảo dự án bình thường. Ngoài ra, bạn nhận được lợi ích của các thư viện liên kết tĩnh nếu thư viện gốc của bạn được thiết kế như vậy, đó là một điều tốt (tm).

2

Phil Nash thực sự đạt được những điều lớn. Đây là một trong những lý do chính mà tôi đã sử dụng C++/CLI trong quá khứ:

Một số ứng dụng được mở rộng ở tất cả các vị trí. Trong C#, không có cách nào để khai báo xuất bản kiểu C gốc, nhưng bạn có thể trong C++/CLI. Tôi tạo ra một "wrapper" trong C++/CLI để xuất phương thức, xử lý bất kỳ bản dịch nào của cấu trúc C thành các đối tượng được quản lý và chuyển cuộc gọi đến một assembly được viết bằng C#.

+0

Đó là một ý tưởng rất thú vị, không bao giờ nghĩ về điều đó. –

1

Có một số loại nhất định không có sẵn cho các ngôn ngữ khác, chẳng hạn như mẫu, const và theo dõi xử lý các loại giá trị được đóng hộp.

mẫu chuyên biên dịch. generics chuyên về thời gian chạy. Mặc dù CLR nên cache chuyên ngành generics để sử dụng trong tương lai (vì vậy bạn nhận được cùng một List mỗi khi bạn sử dụng nó), vẫn có một hiệu suất hit mỗi khi một chuyên ngành generics được yêu cầu.

tôi biết các ngôn ngữ khác loại bỏ thuộc tính const, nhưng phải kiểm tra thời gian biên dịch trong mã C++ của bạn thì tốt hơn là không có gì.

Có loại như int^cho phép bạn truy cập bộ nhớ trên thư mục heap được quản lý mà không cần mở hộp thư không cần thiết. Điều này có thể giúp hiệu suất khi vượt qua các chốt điều khiển theo dõi của các giá trị được đóng hộp đến các hàm mong đợi xử lý theo dõi, chẳng hạn như Console :: WriteLine (Object ^). Tất nhiên khởi động boxing sớm không thể tránh được. Trong các ngôn ngữ khác, bạn có thể lưu trữ các tham chiếu trong một biến Object và vượt qua nó xung quanh để tránh unboxing, nhưng bạn bị mất kiểm tra kiểu thời gian biên dịch.

+0

Generics không phải là mẫu. Sẽ có hiệu suất được nhấn vào lần đầu tiên bạn truy cập vào phiên bản được nhập tham chiếu của phần chung. Sau khi thực hiện mặc dù nó sẽ tái sử dụng cùng một loại tài liệu tham khảo chung cho tất cả các loại mà sẽ không gọi trình biên dịch. Rõ ràng mặc dù nếu bạn có một loại biên dịch sẵn cho một đối tượng nhất định thông qua các mẫu thì sẽ nhanh hơn. – Spence

+1

Việc tái sử dụng được thực hiện bằng cách kiểm tra bộ nhớ cache loại chung. Việc kiểm tra không phải là miễn phí. –

+0

Generics không phải là chuyên ngành cả. –

Các vấn đề liên quan