如何将在C#列表中创建的对象的地址传递给C ++ dll?

| 我一直在Google各处寻找有关我的问题的一些答案,但对我所发现的却不太了解。使用System.IO读取一些文本文件后,我创建了一些对象并将其存储在C#列表中。之后,我想将对每个对象的引用(使用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<SimpleClass> 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<const SimpleClass* > type
}
我试过的是:
for(int i=0; i<ItemList.Count;++i)
{
    SimpleClass theSimpleItem = ItemList[i];
    AddSimpleReference(theSimpleItem);
}
最初,我认为仅使用赋值运算符就可以很容易地获得实际的引用/地址,因为C#中的类是按引用传递的,但事实证明C ++类始终在推送相同的地址值(地址值而不是实际地址)。如何获取实际的对象地址并将其发送到C ++ DLL,以便它可以对C#对象进行只读访问? 更新:对那些发布带有不安全代码的答案的人表示抱歉。我忘了提到C#代码实际上是Unity游戏引擎中的脚本,它不允许使用不安全的代码。     
已邀请:
        首先,您需要更改互操作签名以获取指针(因此使其不安全)。
[DllImport(\"SimpleDLL\")]
public unsafe static extern void AddSimpleReference(SimpleClass* inSimple);
然后,由于GC可以根据需要随意在内存中移动对象,因此您需要在整个时间将对象固定在内存中,并将其地址放在非托管端。为此,您需要“ 7”语句:
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<ItemList.Count;++i)
{
    SimpleClass theSimpleItem = ItemList[i];
    // take a pinned handle before passing the item down.
    GCHandle handle = GCHandle.Alloc(theSimpleItem, GCHandleType.Pinned);
    AddSimpleReference(GCHandle.ToIntPtr(handle));
    // probably a good idea save this handle somewhere for later release
}

// ----
// when you\'re done, don\'t forget to ensure the handle is freed
// probably in a Dispose method, or a finally block somewhere appropriate
GCHandle.Free(handle);
当执行这样的操作时,请记住长时间将对象固定在内存中是一个坏主意,因为这会阻止垃圾收集器有效地完成其工作。     
        即使我认为这不是一个好主意,请查看不安全的代码和内存固定。这是MSDN上的一个好的开始。 固定和不安全的关键字可能是您应该寻找的。     
        你不能。 C#GC将移动对象很有趣。您的地址将超出范围。     

要回复问题请先登录注册