Wie kann ich feststellen, ob ich eine meiner Schnittstellen mit IDisposable erweitern oder IDisposable für eine Klasse implementieren soll, die meine Schnittstelle implementiert?
Ich habe eine Schnittstelle, die außer einer bestimmten Implementierung keine externen Ressourcen benötigt. Meine Optionen scheinen zu sein:
1) Implementieren Sie IDisposable auf der Schnittstelle, die alle Implementierungen erfordert, um Dispose zu implementieren, selbst wenn es sich nur um eine leere Methode handelt.
-oder -
2) Implementieren Sie IDisposable nur für die Klassen, für die Ressourcen bereitgestellt werden müssen. Dies wird zu Problemen bei der Verwendung führen, da mein Objekt aus einer Factory erstellt wird und daher der gesamte Upstream-Code gegen die Schnittstelle arbeitet. Da die Schnittstelle nicht an IDisposable gebunden ist, zeigt "using" die Dispose-Methode nicht. Allerdings könnte ich das Factory-Ergebnis auf die Implementierung übertragen; Dies macht jedoch den Verbraucher auf die Implementierung aufmerksam und vereitelt den Zweck von Schnittstellen.
Irgendwelche Ideen zu Best Practices?
Wenn Sie erwarten, dass Anrufer nur mit der Schnittstelle und niemals mit der Implementierung interagieren können, möchten Sie, dass die Schnittstelle IDisposable
erweitert. Wenn nicht, müssen sie prüfen, ob die value is IDisposable
trotzdem sehen, ob sie entsorgt werden muss.
Wenn das Objekt, das für die Entsorgung des Objekts verantwortlich ist, von der konkreten Implementierung weiß und nur Objekte, die Referenzen darauf erhalten (aber nicht dafür verantwortlich sind), die die Schnittstelle verwenden, dann berücksichtigen Sie die zweite Option.
Ein gutes Beispiel für die erste Option ist IEnumerator
. Viele IEnumerator
-Objekte brauchen nichts zu tun, wenn sie entsorgt werden, aber einige tun das, und deshalb erweitert die Schnittstelle IDisposable
, weil das Objekt, das für die Erstellung / den Lebenszyklus dieses Objekts verantwortlich ist, niemals Wissen haben wird (oder sollte) der zugrunde liegenden Implementierung.
Ein Beispiel für die zweite wäre etwas wie IComparer
viele Objekte, die verglichen werden müssen, sind wegwerfbar, aber die Codeabschnitte, die ein Objekt über die Schnittstelle verwenden, sind nicht für die Erstellung verantwortlich / Lebenszyklus, so dass es keine Kenntnis davon benötigt, ob dieser Typ verfügbar ist oder nicht.
Die $ 50.000-Frage lautet, ob die Verantwortung für die Entsorgung jemals zusammen mit der Schnittstelle übertragen wird, oder, anders ausgedrückt, ob die letzte Entität, die ein implementierendes Objekt verwendet, etwas anderes als die Entität ist, die sie erzeugt.
> Der große Grund dafür, dass IEnumerator<T>
implements IDisposable
implementiert, besteht darin, dass implementierende Objekte von Objekten erstellt werden, die IEnumerable<T>.GetEnumerator()
implementieren, dann aber von anderen Objekten verwendet werden. Das Objekt, das IEnumerable<T>
implementiert, weiß, ob die zurückgegebene Nachricht wirklich gelöscht werden muss, aber es wird nicht möglich sein zu wissen, wann der Empfänger damit fertig ist. Der Code, der IEnumerable<T>.GetEnumerator()
aufruft, weiß, wann er mit dem zurückgegebenen Objekt fertig ist, kann aber nicht wissen, ob eine Bereinigung erforderlich ist. Sinnvollerweise muss angegeben werden, dass der Code, der IEnumerable<T>.GetEnumerator()
aufruft, erforderlich ist, um sicherzustellen, dass das zurückgegebene Objekt Dispose
aufgerufen hat, bevor es abgebrochen wird. Die Dispose
-Methode wird in vielen Fällen nichts tun, aber bedingungsloses Aufrufen einer do-nothing-Methode, die garantiert existiert, ist billiger als das Prüfen auf das Vorhandensein einer Methode, die nicht existiert.
Wenn die Art Ihres Schnittstellentyps so ist, dass die Fragen, ob ein Implementierungsobjekt eine Bereinigung benötigt und wann eine solche Bereinigung stattfinden soll, beide von derselben Entität zu verantworten sind, muss die Schnittstelle nicht erben IDisposable
. Wenn Instanzen von einer Entität erstellt werden, aber zuletzt von einer anderen Entität verwendet werden, wäre die Vererbung von IDisposable
sinnvoll.
Wenn Sie IDisposable
für die konkrete Klasse implementieren und die Benutzer der Benutzeroberfläche wissen, dass es sich um Disposable handeln könnte; Sie können
Wenn foo
IDisposable
nicht implementiert, wird using
auf using(null)
gesetzt, was gut funktioniert.
Die Ausgabe des folgenden Beispielprogramms ist
%Vor%Beispielprogramm
%Vor%Tags und Links c# dispose idisposable