2016-06-29 31 views
0

Angenommen implementieren, dass ich die folgenden Klassen:Wie Sie sich richtig Einweg-Muster mit Bibliotheken von Drittanbietern

class Foo : IDisposable 
{ 
    public void Dispose() 
    { 
    bar.Dispose(); 
    } 

    private Bar bar = new Bar(); 
} 

class Bar : IDisposable 
{ 
    public void Dispose() 
    { 
    baz.Dispose(); 
    } 

    private SomeThirdPartyLibraryClass baz = new SomeThirdPartyLibraryClass(); 
} 

Dieser Code funktioniert gut, wenn using Anweisung:

using (Foo foo = new Foo()) 
{ 
    // ... 
} 
// All resources should be disposed at this time 

jedoch für einige, wenn Grund Benutzer dieser Klasse vergessen, using Anweisung zu verwenden, Ressourcen werden nie entsorgt werden.

Laut MSDN, sollte ich Einweg-Muster auf die folgende Weise implementieren:

class Foo : IDisposable 
{ 
    public void Dispose() 
    { 
    Dispose(true); 
    GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
    if (disposed) 
     return; 

    if (disposing) { 
     // Free any managed objects here. 
     // 
    } 

    // Free any unmanaged objects here. 
    // 
    disposed = true; 
    } 

    ~Foo() 
    { 
    Dispose(false); 
    } 

    bool disposed = false; 
    private Bar bar = new Bar(); 
} 

(das gleiche gilt für Bar)

Aber wo genau soll ich bar.Dispose(); und baz.Dispose(); Code platzieren?

Sollte es unter "verwaltete Aufräumarbeiten" oder unter "nicht verwaltete Aufräumarbeiten" sein?

Wie der Name schon sagt, weiß ich nicht die Implementierung von SomeThirdPartyLibraryClass (und auf jeden Fall kann es im Laufe der Zeit geändert werden).

Was soll ich dann tun?

+0

Wo auf MSDN empfiehlt es, einen Finalizer als Teil einer generischen IDisposable-Implementierung zu verwenden? – stuartd

+0

Mögliches Duplikat von [Ist es möglich, die Verwendung von "using" für Einwegklassen zu erzwingen?] (Http://stackoverflow.com/questions/2675504/is-it-possible-to-force-the-use-of-use-of- Verwendung für Einweg-Klassen) Da Sie Ihre Drittanbieter-Bibliothek nicht ändern können. Es enthält auch einige Verpackungslösungen. – Panda

+0

@stuartd https://msdn.microsoft.com/ru-ru/library/fs2xkftw(v=vs.110).aspx. Nein? – FrozenHeart

Antwort

1

Sie sollten Dispose von bar und baz im verwalteten Abschnitt von Dispose aufrufen, da dies für Ihre Klasse verwaltete Objekte sind. Wenn bar und baz etwas nicht verwaltet haben, sollte das von ihren jeweiligen Klassen in ihrer Dispose/Finalize-Implementierung bereinigt werden.

+0

Also in meinem Fall kann ich die 'Dispose (bool)' 'Methoden und Finalizer überspringen und einfach meine Daten Mitglieder entsorgen und 'GC.SuppressFinalize (this);' direkt in der 'Dispose()' Methode aufrufen? – FrozenHeart

+1

Ja, das macht Sinn, aber da Sie Finalize jetzt nicht implementieren, ist SupressFinalize nicht erforderlich. –

+0

@DeepakBhatia: Wenn eine Klasse, die Verweise auf Objekte mit Finalizern enthält, keinen Zugriff auf das '' '' Ende ihrer 'Dispose' Methode in einer Weise bietet, die nicht nachbestellt werden kann, können diese Finalizer in einigen Fällen vor dem' 'laufen Die Dispose-Funktion ist beendet. Das Aufrufen von 'GC.KeepAlive (this)' oder 'GC.SuppressFinalize (this)' ist ein kostengünstiger Weg, um sicherzustellen, dass weder 'this' noch irgendetwas, auf das' this' verweist, für die Sammlung geeignet sind. – supercat

1

Aber wo genau sollte ich bar.Dispose() setzen; und baz.Dispose(); Code?

Da Ihre Third-Party-Bibliothek als verwalteter Code zu betrachten ist, würde sie in den Bereich "Verwaltete Bereinigung" verschoben.

+0

Also kann ich in meinem Fall das' Dispose 'überspringen (bool) 'Methoden und Finalizer und einfach meine Daten Mitglieder entsorgen und' GC.SuppressFinalize (this); 'direkt in der' Dispose() 'Methode aufrufen? – FrozenHeart

+1

Ich weiß nicht, warum Sie "GC.SuppressFinalize (this)" aufrufen würden, wenn Sie die einfache Methode verwenden. Der einfache Weg ist aber in Ordnung. Fügen Sie Ihrer verwalteten Disposal-Ressource in Ihrer eigenen Dispose-Implementierung einen Aufruf hinzu. – nvoigt

+0

@nvoigt: Der Aufruf von 'GC.SuppressFinalize (this)' oder 'GC.KeepAlive (this)' schützt vor einigen seltenen, aber schwer zu diagnostizierenden Problemen, wenn die Klasse Referenzen auf Objekte mit Finalizern enthält, indem sichergestellt wird, dass die Finalizer kann nicht laufen, bis die Entsorgung abgeschlossen ist. – supercat