C# 在非托管内存中保存对托管对象的引用

C# 在非托管内存中保存对托管对象的引用,c#,c,pinvoke,C#,C,Pinvoke,我想把对C对象的引用放到非托管内存C中,我猜是指针int,当C代码稍后调用C时,我想从非托管内存中获取引用,以便解析它并访问该对象。原因是C代码控制应该使用哪个对象,没有真正的选择。我对C代码的控制有限,C++/CLI不是一个选项 问题:这是否可能且安全,如果可能,如何实现?当您控制“分发”和“接收后使用”阶段时,您只需使用列表或数组并传递索引即可 可以通过COM和被调用的CLR创建的代理使用C对象 您只需分配GUID程序集属性来标识COM类型库,例如: [assembly: Guid ("39

我想把对C对象的引用放到非托管内存C中,我猜是指针int,当C代码稍后调用C时,我想从非托管内存中获取引用,以便解析它并访问该对象。原因是C代码控制应该使用哪个对象,没有真正的选择。我对C代码的控制有限,C++/CLI不是一个选项


问题:这是否可能且安全,如果可能,如何实现?

当您控制“分发”和“接收后使用”阶段时,您只需使用列表或数组并传递索引即可

可以通过COM和被调用的CLR创建的代理使用C对象

您只需分配GUID程序集属性来标识COM类型库,例如:

[assembly: Guid ("39ec755f-022e-497a-9ac8-70ba92cfdb7c")]
然后使用工具tlbexp.exe生成COM类型库.tlb文件,该文件可在COM世界中使用:

tlbexp.exe YourLibrary.dll

如果你的意思是C意义上的安全,那么肯定是不安全的,因为你将在非托管世界中使用对象,并且生命周期是通过引用计数从COM端控制的,而不是CLR的GC。

好吧,这是可能的。主要的问题是您的方案与垃圾收集器非常不兼容,它在压缩堆时会移动内存中的对象。这是你可以停止的,你可以固定对象,这样GC就不能移动它。您可以使用GCHandle.Alloc分配一个GCHandleType.Pinned句柄,并将GCHandle.AddrOfPinnedObject的返回值传递给您的C代码,可能是通过pinvoke调用

您必须担心该对象需要固定多久。最多几秒钟是可以的,但是如果你把它固定很长时间,它会对GC非常有害。这是一块路中的石头,总承包商必须经常绕道而行。堆段永远不会被回收,单个对象可能会花费你几兆字节

在这种情况下,您应该考虑分配非托管内存并将对象复制到其中。使用Marshal.AllocHGlobal进行分配,使用Marshal.StructureToPtr将对象复制到其中。如果您修改了对象并且更改也需要对C代码可见,那么可能会多次


无论哪种方式,对象都必须是可blittable的,否则会出现运行时错误。这是一个昂贵的词,它只意味着对象必须具有简单的字段类型,C程序有机会正确读取这种类型的字段。不要使用bool。小心C程序中的声明,当你弄错时很容易损坏堆。

谢谢,我会接受这个答案,因为它是最接近我想要的东西。是的,我可以做到。这个问题的原因是,可能会有很多调用来自非托管端,我敢打赌,将指针投射到对象可能比在字典中查找值更快。出于某种原因,我没有想到使用列表或数组。我可能会这样做,谢谢xD