Warum IEnumerator von IDisposable erbt, während der nicht-generische IEnumerator nicht?
-
04-07-2019 - |
Frage
Ich habe bemerkt, dass der generische IEnumerator<T>
von IDisposable erbt, aber die nicht-generische Schnittstelle IEnumerator nicht. Warum ist es auf diese Weise gestaltet?
Normalerweise verwenden wir foreach-Anweisung durch eine IEnumerator<T>
Instanz zu gehen. Der generierte Code von foreach hat tatsächlich versuchen-finally-Block, der in schließlich Dispose () aufruft.
Lösung
Im Grunde war es ein Versehen. In C # 1.0, foreach
nie genannt Dispose
1 . Mit C # 1.2 (in VS2003 eingeführt - es gibt keine 1.1, bizarr) foreach
im finally
Block zu prüfen begann, ob der Iterator implementiert IDisposable
- sie es auf diese Weise zu tun hatte, weil nachträglich IEnumerator
IDisposable
verlängern machen würde gebrochen Umsetzung der alle haben von IEnumerator
. Wenn sie heraus gearbeitet haben, dass es nützlich ist für foreach
von Iteratoren an erster Stelle zu entsorgen, ich bin sicher, dass IEnumerator
würde IDisposable
erweitert hat.
Wenn C # 2.0 und .NET 2.0 herauskommt, aber sie hatten eine neue Chance - neue Schnittstelle, neue Vererbung. Es macht viel mehr Sinn die Schnittstelle zu haben IDisposable
zu erweitern, so dass Sie nicht eine Ausführungszeitprüfung im finally-Block brauchen, und jetzt der Compiler weiß, dass, wenn der Iterator ein IEnumerator<T>
ist, kann es einen unbedingten Aufruf emittieren Dispose
.
EDIT: Es ist unglaublich nützlich für Dispose
am Ende der Iteration aufgerufen werden (aber es endet). Es bedeutet, dass der Iterator auf Ressourcen festhalten kann - was es möglich macht, dafür zu, sagen wir, eine Datei Zeile für Zeile lesen. Iterator Blöcke erzeugen Dispose
Implementierungen, die sicherstellen, dass alle finally
Blöcke relevant für den „aktuellen Punkt der Ausführung“ des Iterators ausgeführt werden, wenn sie entsorgt wird -. So können Sie normalen Code innerhalb des Iterator und clean-up sollte in geeigneter Weise geschehen schreiben
1 Rückblick auf die 1.0-Spezifikation, es wurde bereits festgelegt. Ich habe noch nicht gelungen, diese frühere Aussage zu verifizieren, dass die 1.0 Implementierung nicht Dispose
angerufen hat.
Andere Tipps
IEnumerable
Ich denke, die allgemeine Enumerator
Ich weiß, dass dies eine alte Diskussion, aber ich schrieb reasontly eine Bibliothek, wo ich IEnumerable von T / IEnumerator von T verwendet, in denen Benutzer der Bibliothek können auch eigene Iteratoren implementieren sollten sie nur IEnumerator von T implementieren.
Ich fand es sehr merkwürdig, dass IEnumerator von T von IDisposable erben würde. Wir implementieren IDisposable, wenn wir unmanged Ressourcen richtig befreien wollen? So wäre es nur für Enumeratoren relevant sein, die tatsächlich nicht verwalteten Ressourcen halten - wie ein IO-Stream usw. Warum nicht nur Benutzer lassen sowohl IEnumerator von T und IDisposable auf ihrem enumerator implementieren, wenn es Sinn macht? In meinem Buch verletzt dies die einzige Verantwortung Prinzip - Warum enumerator Logik und Entsorgung Objekte mischen.
Hat IEnumerable` IDisposing erben? Gemäß dem Reflektor oder .NET MSDN . Sind Sie sicher, dass Sie verwirren nicht mit IEnumerator ? Das nutzt IDisposing, weil es nur für eine Sammlung aufzählt und nicht für Langlebigkeit gemeint.
Ein bisschen hart daran endgültig zu sein, es sei denn Sie eine Antwort von Andersh selbst oder jemand nah an ihm bekommen verwalten.
Aber meine Vermutung ist, dass es auf die „Ausbeute“ Schlüsselwort bezieht, die in C # zur gleichen Zeit eingeführt wurde. Wenn Sie die vom Compiler erzeugten Code zu buchen, wenn „yield return x“ verwendet wird, müssen Sie die Methode sehen in einer Hilfsklasse eingewickelt, die IEnumerator implementiert; IEnumerator von IDisposable absteigen, die sicherstellt, dass es aufzuräumen kann, wenn Enumeration abgeschlossen ist.
IIRC Das Ganze über IEnumerable<T>
und IEnumerable
hat, ist ein Ergebnis der IEnumerable
.Net Vorlage Zeug datierend. Ich vermute, dass Ihre Frage in der gleichen Art und Weise ist.