2013-06-06 12 views
5

Ich habe eine C++/CLI-Klasse namens "CTransferManaged" mit implementierter Finalizerthread und destructor:C#/CLI: Destructor nicht aufgerufen, wenn Dispose(), die in es

CTransferManaged::~CTransferManaged() 
{ 
    this->!CTransferManaged(); 
} 
CTransferManaged::!CTransferManaged() 
{ 
    //Clean up resources... 
} 

Diese Klasse mit einer C# Klasse mit dem Namen gewickelt "CTransfer" enthält ein Objekt m_transfer vom Typ CTransManaged.

Wenn der Destruktor dieser Klasse löscht nur die Referenz auf das Objekt m_transfer ich sehen kann, dass der Destruktor aufgerufen wird (Haltepunkt getroffen wird):

~CTransfer() 
{ 
    m_transfer = null; //breakpoint on this line 
} 

Wenn ich rufen Sie die Dispose() Funktion des m_transfer Objekt, ohne etwas anderes zu ändern, wird der Destruktor nicht mehr aufgerufen (Haltepunkt kein Treffer mehr). Irgendwelche Vermutungen warum?

~CTransfer() 
{ 
    m_transfer.Dispose(); //breakpoint on this line 
    m_transfer = null; 
} 

Ich möchte Dispose() aufrufen, manuell, da ich, dass die Ressourcen des C herausgefunden ++/CLI-Objekt (m_transfer) nicht richtig gereinigt, wenn ich nicht manuell entsorgen nennst. Im Moment weiß ich nicht genau warum.

Warum wird der Destruktor von CTransfer (C# -Klasse) nicht mehr aufgerufen, sobald er CTransferManaged :: Dispose() (C++/CLI) aufruft?

+0

Ihre CTransfer-Klasse * muss IDisposable implementieren, damit sie das m_transfer-Mitglied ordnungsgemäß entsorgen kann. Sieht so aus, als hättest du das getan. Setzen Sie ** nicht ** einen Finalizer für CTtransfer ein. Das Festlegen eines Members auf null hat keinen nützlichen Effekt und der Aufruf der Dispose() -Methode ist einfach falsch. –

+0

@HansPassant: Warum ist es falsch, die Dispose() - Methode eines Mitgliedsobjekts (m_transfer) im Finalizer von CTransfer aufzurufen? Wie ich bereits erwähnt habe, habe ich herausgefunden, dass die Ressourcen von m_transfer nicht richtig aufgeräumt werden, wenn ich Dispose() nicht darauf anrufe ( obruend

Antwort

0

C# -Destruktor wird nur vom Garbage Collector aufgerufen und Sie können ihn nicht direkt aufrufen.

Dispose, das Teil der IDisposalbe-Schnittstelle ist, sollte nur manuell aufgerufen werden und der Destruktor wird nicht ausgelöst.

Anstatt auf Destruktor angewiesen zu sein, versuchen Sie, iDisposabe zu implementieren, und rufen Sie die Dispose-Methode direkt auf und geben Sie Ihren Code dort ein.

Wenn die Ressourcenklasse eingebettete Objekte enthält, die entsorgt werden soll, wird dieses Muster mit C# erforderlich:

// C# 
public class Resource : IDisposable 
{ 
    private EmbeddedResource embedded; 

    public Resource() 
    { 
     Console.WriteLine("allocating resource"); 
     embedded = new EmbeddedResource(); 
    } 

    ~Resource() 
    { 
     Dispose(false); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     Console.WriteLine("release resource"); 
     if (disposing) 
     { 
     embedded.Dispose(); 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 
} 
+0

Beachten Sie, dass ich das C# -Objekt (Klasse CTransfer) nicht manuell Dispose() möchte. Ich möchte nur die manuelle Entsorgung seines Members m_transfer (Klasse CTransferManaged) verwenden, da seine Ressourcen sonst nicht richtig aufgeräumt werden. – obruend

0

Das typische Muster für Entsorgung und Finalisierung ist so, dass, wenn Sie Dispose aufrufen, sollte die Finalizerthread unterdrückt werden . Dispose dient zum Löschen von Ressourcen, sobald sie ausgeführt wird, während der Finalizer Ressourcen löschen soll, wenn der Garbage Collector die Klasse sammelt ... Beide sollen dasselbe tun (freigegebene nicht verwaltete Ressourcen freigeben), und wenn Sie also anrufen Dispose, das Aufrufen des Finalizers wäre dann redundant und unnötig und würde außerdem dazu führen, dass das Objekt länger als benötigt am Leben bleibt, da es zuerst in der Finalizer-Warteschlange platziert wird, bevor es gesammelt und zerstört wird. Dies führt zu einer schlechten Speicherverwaltung für Anwendungen mit hohem Zugriff, die viele Objekte erstellen und löschen. Daher rufen die meisten Dispose-Methoden in C# auf:

Welche teilt der Müllabfallsammler, den Finalizer nicht zu tun. Dieses Muster wird häufig verwendet und wird wahrscheinlich auch in Ihrer nicht verwalteten Klasse verwendet. Dies ist wahrscheinlich der Grund, warum der Dispose-Aufruf den Destruktor eliminiert.