作为Hans Passant 希望,这是我的情况。我有一个混合模式应用程序,其中本机代码完成所有艰苦的工作,同时尊重性能,托管代码仅负责GUI。此外,用户将通过编写专有的C#代码参与其中。我有本机类的C++,GUI和用户代码以及中间包装器类的C++/Cli。在我所有的C++类中,有一个类占据了90%的计算,并且每次都会创建不同的参数。让我们称之为NativeClass。有大约2000个此NativeClass实例,我必须在进行计算之前找到与某些参数相关的正确实例。因此,我设计了一个hash_map,其中参数是哈希码,用于此目的。当我获得参数时,在hash_map中寻找正确的实例,找到它并调用一些方法。
当用户通过编写C#代码参与计算并且该类通过回调执行这些代码时,这很平凡。但有时我需要一些关于用户构建的.NET类的信息。因此,我需要以某种方式将特定的ManagedClass附加到NativeClass。我的第一个解决方案是使用GChandle.Alloc()并传输句柄地址。但是,有一些担忧关于GC它不会正确地完成其工作。Hans建议使用Marshal.AllocCoTaskMem()和Marshal.StructureToPtr()在非托管内存中分配托管对象,但是我认为这对于值类型类或结构是有效的。那么引用类怎么办?我如何传递对NativeClass的引用,同时防止它们被GC收集并使GC同时正常工作?
这里是一些示例代码:
class NativeClass
{
private:
int AddressOfManagedHandle;
public:
static NativeClass * GetNativeClassFromHashMap(int SomeParameter)
{
// return NativeClass associated with SomeParameter from NativeClassHashMap;
}
NativeClass(int addr, int SomeParameter) : AddressOfManagedHandle(addr)
{
}
int GetAddress(){return AddressOfManagedHandle;}
void DoCalculation(){
// CALCULATIONS
}
};
public ref class ManagedClass : MarshalByRefObject
{
private:
NativeClass* _nc;
//GCHandle handle;
void FreeManagedClass()
{
Marshal::FreeHGlobal(IntPtr(_nc->GetAddress()));
//if(handle.IsAllocated)
//handle.Free();
delete _nc;
}
public:
ManagedClass()
{
IntPtr addr = (Marshal::AllocHGlobal(Marshal::Sizeof(this))); // Error
Marshal::StructureToPtr(this,addr,true);
//handle = GCHandle.Alloc(this);
//IntPtr addr = handle.ToIntPtr();
_nc = new NativeClass(addr.ToInt32());
}
~ManagedClass() {FreeManagedClass();}
!ManagedClass() {FreeManagedClass();}
int GetAddress() {return _nc->GetAddress();};
static ManagedClass^ GetManagedClass(int SomeParameter)
{
int addr = NativeClass::GetNativeClassFromHashMap(SomeParameter)->GetAddress();
//Object^obj = GCHandle::FromIntPtr(IntPtr(addr)).Target;
Object^ obj = Marshal::PtrToStructure(IntPtr(addr), ManagedClass::typeid );
return dynamic_cast<ManagedClass^>(obj);
}
};
很抱歉,这篇文章太长了,而且还不够清晰易懂。