2010-10-07 3 views
7

Tôi có một ứng dụng lớn được viết bằng ngôn ngữ gốc C++. Tôi cũng có một lớp trong C# mà tôi cần phải gọi.C++ Interop: Làm thế nào để gọi một lớp C# từ bản C++, với việc xoay lớp không tĩnh?

Nếu lớp C# là tĩnh, thì nó sẽ là tầm thường (có rất nhiều ví dụ trên web) - chỉ cần viết trình bao hỗn hợp C++/CLI, xuất giao diện và bạn đã hoàn tất.

Tuy nhiên, lớp C# không tĩnh và không thể thay đổi thành tĩnh vì nó có giao diện (trình biên dịch sẽ tạo ra lỗi nếu bạn cố gắng tạo lớp C# tĩnh).

Có ai đó gặp sự cố này trước đây không - làm cách nào để xuất một lớp C# không tĩnh thành bản C++?


Cập nhật 2010-11-09

giải pháp cuối cùng: cố gắng COM, điều này làm việc độc đáo nhưng không hỗ trợ cấu trúc. Vì vậy, đã đi với một wrapper C++/CLI, bởi vì tôi hoàn toàn cần thiết để có thể vượt qua các cấu trúc giữa C + + và C#. Tôi đã viết một chế độ hỗn hợp .dll wrapper dựa trên mã ở đây:

Như lớp mục tiêu là không tĩnh, tôi đã phải sử dụng singleton để đảm bảo rằng tôi chỉ đang tạo một bản sao của lớp đích. Điều này đảm bảo mọi thứ đã đủ nhanh để đáp ứng các thông số kỹ thuật.

Liên hệ với tôi nếu bạn muốn tôi đăng dự án demo (mặc dù, công bằng, tôi gọi C# từ C++, và những ngày này hầu hết mọi người muốn gọi C++ từ C#).

+0

Tôi biết tôi sẽ cần điều này trong một vài tuần, vì vậy tôi rất quan tâm đến câu trả lời. – dwo

+0

Chết tiệt, đó là một cái nhìn giống như cưa. Ngay ở cuối câu hỏi, khi bạn ít mong đợi nhất! –

Trả lời

10

C++/CLI hoặc COM interop hoạt động tốt với các lớp không tĩnh như tĩnh. Sử dụng C++/CLI, bạn chỉ tham chiếu đến assembly của bạn mà giữ lớp không tĩnh và sau đó bạn có thể sử dụng gcnew để lấy một tham chiếu đến một cá thể mới.

Điều gì khiến bạn nghĩ rằng điều này là không thể với lớp không tĩnh của bạn?

CHỈNH SỬA: có mã mẫu here.

using namespace System; 

public ref class CSquare 
{ 
private: 
    double sd; 

public: 
    CSquare() : sd(0.00) {} 
    CSquare(double side) : sd(side) { } 
    ~CSquare() { } 

    property double Side 
    { 
    double get() { return sd; } 
    void set(double s) 
    { 
     if(s <= 0) 
     sd = 0.00; 
     else 
     sd = s; 
    } 
    } 

    property double Perimeter { double get() { return sd * 4; } } 
    property double Area { double get() { return sd * sd; } } 
}; 

array<CSquare ^>^CreateSquares() 
{ 
    array<CSquare ^>^sqrs = gcnew array<CSquare ^>(5); 

    sqrs[0] = gcnew CSquare; 
    sqrs[0]->Side = 5.62; 
    sqrs[1] = gcnew CSquare; 
    sqrs[1]->Side = 770.448; 
    sqrs[2] = gcnew CSquare; 
    sqrs[2]->Side = 2442.08; 
    sqrs[3] = gcnew CSquare; 
    sqrs[3]->Side = 82.304; 
    sqrs[4] = gcnew CSquare; 
    sqrs[4]->Side = 640.1115; 

    return sqrs; 
} 
+0

Tôi quyết định đi với COM. Quan tâm của chúng tôi, bạn có biết của bất kỳ ví dụ về một wrapper C++/CLI instantiating một lớp không tĩnh trong C#? Tôi không thể nhận được xung quanh các lỗi trình biên dịch, không có vấn đề gì tôi đã cố gắng, và không ai trong số các ví dụ của trang web được cho bất cứ điều gì khác hơn là một lớp tĩnh. – Contango

+0

@Gravitas - xem chỉnh sửa –

+0

Tuyệt vời, cảm ơn. Để hoàn thành, mã nguồn bạn tham chiếu được thiết kế cho MSVS 2003 và sẽ không hoạt động trừ khi được nâng cấp lên MSVS 2005, hướng dẫn và nguồn cập nhật có tại http://msdn.microsoft.com/en-us/magazine/cc163602. aspx (cảm ơn @Sergey). – Contango

3

Hai tùy chọn cần lưu ý.

  1. Hiển thị lớp dưới dạng đối tượng COM và sử dụng nó làm đối tượng COM từ C++.
  2. Tạo lớp C# tĩnh cho thấy giao diện tương tác với lớp C# không tĩnh.
+0

Tôi quyết định đi với COM, và nó hoạt động hoàn hảo. Cảm ơn bạn rất nhiều vì đã trả lời câu hỏi này - được nhiều người đánh giá cao. – Contango

1

Tôi đã nghiên cứu chủ đề này vài năm trước: Tôi muốn sử dụng các thư viện log4net và Npgsql từ mã gốc để biên dịch ngay cả khi không có khóa/clr.

Ý tưởng chính đằng sau kỹ thuật này được mô tả bởi Paul DiLascia trong hai bài báo đáng chú ý của mình:

Managed Code in Visual Studio 2005

Use Our ManWrap Library to Get the Best of .NET in Native C++ Code

Ý tưởng chính trong giải pháp này mà gcroot con trỏ thông minh và intptr_t có giống hệt nhau đại diện trong bộ nhớ. Và chúng tôi tạo ra một macro gọi là GCROOT (T) sử dụng gcroot trong Managed code và intptr_t trong unmanaged. Và chúng tôi tạo ra DLL với giao diện nguyên bản và quản lý thực hiện và sử dụng dll này từ mã nguồn gốc của chúng tôi. Nó là khá dễ dàng cho tôi tạo ra một số adapter cho các lớp học quản lý của tôi và sử dụng chúng trong thế giới C++ bản địa và biên dịch mã nguồn của tôi ngay cả khi không có/clr key.

+0

Tôi đã xem xét mã bạn tham chiếu và có vẻ rất dễ sử dụng: Tôi sẽ triển khai cả COM và mã ở trên và chỉnh sửa câu hỏi ban đầu của tôi để sửa nó. Cảm ơn nhiều! – Contango