2013-06-06 16 views
5

Ho una classe C++/CLI denominato "CTransferManaged" con finalizzatore e distruttore implementato:C#/CLI: Destructor non chiamato se Dispose() utilizzato in esso

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

Questa classe è avvolto con una classe C# denominata "CTransfer" contiene un oggetto m_transfer di tipo CTransferManaged.

Se il distruttore di questa classe cancella solo il riferimento all'oggetto m_transfer posso vedere che il distruttore è chiamato (punto di interruzione viene colpito):

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

Se io chiamo la funzione Dispose() del m_transfer oggetto senza cambiare altro, il distruttore non viene più chiamato (punto di interruzione non più colpito). Qualche ipotesi perch?

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

vorrei chiamare Dispose() manualmente da quando ho scoperto che le risorse dell'oggetto C++/CLI (m_transfer) non sono puliti correttamente se non chiamare Dispose manualmente. Al momento non so esattamente perché.

Perché il distruttore di CTransfer (classe C#) non viene più chiamato non appena chiama CTransferManaged :: Dispose() (C++/CLI)?

+0

tuo CTransfer classe * deve * implementare IDisposable in modo che possa smaltire correttamente il membro m_transfer. Sembra che tu l'abbia fatto. ** Non ** implementare un finalizzatore per CTransfer. Impostare un membro su null non ha alcun effetto utile e chiamare il suo metodo Dispose() è semplicemente sbagliato. –

+0

@HansPassant: Perché è errato chiamare il metodo Dispose() di un oggetto membro (m_transfer) all'interno del finalizzatore di CTransfer? Come ho detto, ho scoperto che le risorse di m_transfer non vengono pulite correttamente quando non chiamo Dispose() su di esso ( obruend

risposta

0

C# distruttore solo ottenere chiamato dal garbage collector e non è possibile chiamarlo direttamente.

Dispose che fa parte dell'interfaccia IDisposalbe dovrebbe essere chiamato solo manualmente e non si attiverà il distruttore.

Invece di basarsi su distruttore cercare di attuare iDisposabe e chiamato direttamente il metodo Dispose e inserire il codice lì.

Se la classe di risorsa contiene oggetti incorporati che devono essere smaltiti, questo modello è necessaria con C#:

// 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

Si noti che non voglio eliminare manualmente() l'oggetto C# (classe CTransfer). Voglio solo utilizzare lo smaltimento manuale del suo membro m_transfer (classe CTransferManaged) poiché le sue risorse non vengono correttamente ripulite. – obruend

0

Il modello tipico per lo smaltimento e la finalizzazione è tale che quando si chiama Dispose, il finalizzatore dovrebbe essere soppressa . Smaltire è destinato a cancellare le risorse non appena viene eseguito, mentre il finalizzatore è destinato a cancellare le risorse ogni volta che il garbage collector raccoglie la classe ... Entrambi hanno lo scopo di fare la stessa cosa (rilascio risorse non gestite), e così se si chiama smaltire, chiamando il finalizzatore sarebbe allora ridondante e inutile, e potrebbe anche causare l'oggetto a vivere più a lungo di quanto dovrebbe in quanto sarebbe prima essere posizionato sulla coda Finalizer prima di essere raccolto e distrutto. Ciò causa una scarsa gestione della memoria su applicazioni ad accesso elevato che creano e smaltiscono molti oggetti. Pertanto, la maggior parte dei metodi Dispose in C# chiamerà:

GC.SuppressFinalize(this); 

Che dice al Garbage Collector di non eseguire il finalizzatore. Questo modello è ampiamente utilizzato ed è probabilmente utilizzato anche nella tua classe non gestita. Questo è probabilmente il motivo per cui la chiamata Dispose elimina il distruttore.

Problemi correlati