C ++ Interop:如何从本机C ++调用C#类,并且该类是非静态的?
我有一个用本机C ++编写的大型应用程序。 我还有一个C#课我需要打电话。
如果C#类是静态的,那么它将是微不足道的(Web上有很多例子) – 只需编写混合的C ++ / CLI包装器,导出接口,然后就完成了。
但是,C#类是非静态的,并且不能更改为静态,因为它有一个接口(如果您尝试使C#类静态,编译器将生成错误)。
有没有人遇到过这个问题 – 如何将非静态C#类导出到本机C ++?
更新2010-11-09
最终的解决方案:尝试COM,这很好用,但不支持结构。 所以,使用C ++ / CLI包装器,因为我绝对需要能够在C ++和C#之间传递结构。 我根据这里的代码编写了一个混合模式.dll包装器:
-
如何:使用C ++ Interop的Marshalarrays
-
如何:使用C ++ Interop的Marshal结构
由于目标类是非静态的,我不得不使用单例模式来确保我只实例化目标类的一个副本。 这确保一切都足够快,以满足规格。
如果你想让我发布一个演示项目,请联系我(虽然,公平地说,我从C ++调用C#,而现在大多数人都希望从C#调用C ++)。
与静态类一样,C ++ / CLI或COM互操作也适用于非静态类。 使用C ++ / CLI,您只需引用包含非静态类的程序集,然后您可以使用gcnew
来获取对新实例的引用。
是什么让你觉得这对你的非静态课是不可能的?
编辑:这里有示例代码。
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 ^ CreateSquares() { array ^ sqrs = gcnew array (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; }
我想到了两种选择。
- 将该类公开为COM对象,并将其用作C ++中的COM对象。
- 创建一个静态C#类,公开一个接口以与非静态C#类进行交互。
几年前我已经调查了这个话题:我想使用原生代码中的log4net和Npgsql库,即使没有/ clr键也可以编译。
Paul DiLascia在他的两篇非凡文章中描述了这种技术背后的主要思想:
Visual Studio 2005中的托管代码
使用我们的ManWrap库在Native C ++代码中获得最佳.NET
这个解决方案的主要思想是gcroot智能指针和intptr_t在内存中具有完全相同的表示。 我们创建了一个名为GCROOT(T)的宏,它在托管代码中使用gcroot,在非托管代码中使用intptr_t。 我们使用本机接口和托管实现创建DLL,并使用本机代码中的dll。
我很容易为托管类创建一些适配器并在本机C ++世界中使用它们,即使没有/ clr密钥也可以编译我的源代码。