Als Hans Passant Wünsche Hier ist das Szenario von mir. Ich habe eine Mixed-Mode-Anwendung, in der der native Code die ganze harte Arbeit macht, während er die Leistung respektiert und der verwaltete Code nur für die GUI verantwortlich ist. Auch die Benutzer werden sich beteiligen, indem sie ihren eigenen C#-Code schreiben. Ich habe C++ für native Klassen, C# für GUI und Anwendercode und C++/Cli für Wrapper-Klassen dazwischen. Unter all meinen C++-Klassen gibt es eine, die 90 % der Berechnungen durchführt und jedes Mal einen anderen Parameter erzeugt. Nennen wir sie NativeClass. Es gibt ca. 2000 Instanzen dieser NativeClass und ich muss die richtige Instanz in Bezug auf einen Parameter finden, bevor sie eine Berechnung durchführt. Zu diesem Zweck habe ich eine hash_map entwickelt, wobei die Parameter den Hash-Code darstellen. Wenn ich einen Parameter erhalte, suche ich nach der richtigen Instanz in der hash_map, finde sie und rufe einige ihrer Methoden auf.
Wenn Benutzer Berechnungen durchführen, indem sie C#-Code schreiben und diese Klasse diese Codes durch Rückrufe ausführt. Das ist trivial, aber manchmal brauche ich Informationen über die .Net-Klassen, die die Benutzer erstellt haben. Also muss ich diese spezifische ManagedClass irgendwie mit der NativeClass verbinden. Meine erste Lösung ist die Verwendung von GChandle.Alloc() und die Übergabe der Handle-Adresse. Aber es gibt einige betrifft über GC, dass sie ihre Aufgabe nicht richtig erfüllen wird. Hans empfahl Marshal.AllocCoTaskMem() und Marshal.StructureToPtr(), um verwaltete Objekte in nicht verwaltetem Speicher zuzuweisen, aber ich glaube, dass dies auch für Klassen oder Strukturen vom Typ Wert gilt. Wie sieht es mit ref-Klassen aus? Wie kann ich eine Referenz an eine NativeClass übergeben und gleichzeitig verhindern, dass sie von GC gesammelt wird und dass GC richtig funktioniert?
Hier ist ein Beispielcode:
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);
}
};
Es tut mir leid, dass es zu lang ist und immer noch nicht klar ist.