如何将C#List中创建的对象的地址传递给C ++ DLL?
我一直在谷歌寻找我的问题的一些答案,但不太明白我发现了什么。 在使用System.IO读取一些文本文件后,我有一些在C#List中创建和存储的对象。 之后,我想将每个对象的引用(使用const指针)发送到C ++ dll中的内部类,以便它可以使用它们来计算某些算法。
以下是我正在做的一些简单示例(不是实际代码):
C#类:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class SimpleClass { [MarshalAs(UnmanagedType.LPStr)] public string Name; public float Length; }
与相应的C结构:
struct SimpleClass { const char* Name; float Length; };
存储在
List ItemList;
解析一些文本文件后。
然后调用以下dll函数:
C#:
[DllImport("SimpleDLL")] public static extern void AddSimpleReference(SimpleClass inSimple);
C:
void AddSimpleReference(const SimpleClass* inSimple) { g_Vector.push_back(inSimple); // g_Vector is a std::vector type }
我试过的是:
for(int i=0; i<ItemList.Count;++i) { SimpleClass theSimpleItem = ItemList[i]; AddSimpleReference(theSimpleItem); }
最初,我认为通过使用赋值运算符很容易获得实际的引用/地址,因为C#中的类是按引用传递的,但事实certificateC ++类总是推送相同的地址值(地址值)临时引用)进入容器而不是实际地址。 如何获取实际的对象地址并将其发送到C ++ DLL,以便它可以只读访问C#对象?
更新 :对于那些使用不安全代码发布答案的人抱歉。 我忘了提到C#代码实际上是用作Unity游戏引擎中的一个脚本,它不允许使用不安全的代码。
首先,您需要更改互操作签名以获取指针(从而使其不安全)。
[DllImport("SimpleDLL")] public unsafe static extern void AddSimpleReference(SimpleClass* inSimple);
然后,由于GC可以随心所欲地在内存中移动对象,因此您需要将对象固定在内存中,以便在非托管端需要其地址的整个时间。 为此你需要fixed
声明:
SimpleClass theSimpleItem = ItemList[i]; unsafe { fixed(SimpleClass* ptr = &theSimpleItem) { AddSimpleReference(ptr); } }
如果AddSimpleReference
使用指针然后将其丢弃,这将起作用。 但是你将指针存储在std::vector
以供日后使用。 这将无法工作,因为一旦执行离开fixed
块,GC会将原始项目移动到其他位置,因此指针可能会变得无效。
要解决此问题,您需要固定项目,直到完成它们为止。 为此,您可能需要使用GCHandle
类型。
// Change the interop signature, use IntPtr instead (no "unsafe" modifier) [DllImport("SimpleDLL")] public static extern void AddSimpleReference(IntPtr inSimple); // ---- for(int i=0; i
在做这样的事情时,请记住长时间在内存中固定对象是个坏主意,因为它会阻止垃圾收集器有效地完成其工作。
尽管我认为这不是一个好主意,但请看一下不安全的代码和内存固定。 这是MSDN的一个良好开端。
固定和不安全的关键字很可能是您应该寻找的。
你不能。 C#GC将移动对象以获得乐趣。 您的地址将超出范围。