2010-07-14 18 views
90

Ich habe den folgenden CodeWas passiert, wenn ich vor dem Ende der Verwendung der Anweisung zurückkomme? Wird die Verfügung angerufen?

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

Die dispose() Methode am Ende der using Anweisung aufgerufen wird Zahnspange } richtig? Da ich return vor dem Ende der using Aussage, wird das MemoryStream Objekt ordnungsgemäß entsorgt werden? was geschieht hier?

+4

@JonH: Finden Sie die genaues Duplikat, dann stimmen Sie bitte in diesem Fall ab. – Noldorin

+0

@Noldorin: Ich habe nach einem Betrogenen gesucht, weil ich gedacht habe, dass es vorher gefragt wurde, aber ich konnte keinen finden. Ich denke, es gibt immer noch einfache Fragen. :) – Randolpho

+0

@JonH und @Noldorin - Duplikate wären dargestellt worden, als die Frage gestellt wurde, sie sucht nach "ähnlichen Fragen", eine Eigenschaft, die Leute anscheinend nicht genug benutzen. –

Antwort

137

Ja, Dispose wird aufgerufen. Es wird aufgerufen, sobald die Ausführung den Gültigkeitsbereich des Blocks using verlässt, unabhängig davon, was es bedeutet, den Block zu verlassen, sei es das Ende der Ausführung des Blocks, eine return-Anweisung oder eine Ausnahme.

Wie @Noldorin Punkte korrekt aus, ein using Block in Code kompiliert wird in try/finally, mit Dispose im finally Block genannt wird. Zum Beispiel der folgende Code:

using(MemoryStream ms = new MemoryStream()) 
{ 
    //code 
    return 0; 
} 

wirksam wird:

MemoryStream ms = new MemoryStream(); 
try 
{ 
    // code 
    return 0; 
} 
finally 
{ 
    ms.Dispose(); 
} 

Also, weil finally garantiert ausgeführt werden, nachdem die try Blockausführung, unabhängig von ihrer Ausführungspfad beendet ist, wird Dispose garantiert sein genannt, egal was.

Weitere Informationen finden Sie unter this MSDN article.

Nachtrag:
Nur eine wenig Einschränkung hinzuzufügen: weil Dispose garantiert genannt werden, ist es fast immer eine gute Idee, um sicherzustellen, dass Dispose nie eine Ausnahme auslöst, wenn Sie IDisposable implementieren. Leider gibt es einige Klassen in der Core-Bibliothek, die tun unter bestimmten Umständen zu werfen, wenn Dispose aufgerufen wird - ich freue mich auf Sie, WCF-Service-Referenz/Client-Proxy! - und wenn das passiert, kann es sehr schwierig sein, die ursprüngliche Ausnahme aufzuspüren, wenn Dispose während eines Ausnahme-Stack-Abwicklers aufgerufen wurde, da die ursprüngliche Ausnahme zugunsten der neuen Ausnahme, die durch den Aufruf Dispose generiert wurde, geschluckt wird. Es kann ärgerlich frustrierend sein. Oder ist das frustrierend verrückt? Einer der Beiden. Vielleicht beide.

+4

Ich denke, Sie werden feststellen, dass es effektiv in einen try-finally-Block kompiliert wird, mit einem Aufruf an 'Dispose' schließlich, also arbeitet es effektiv an der Implementierung von' finally', wie Sie beschreiben. – Noldorin

+0

@Noldorin: genau. Obwohl ich mir das explizit vorstellen könnte. Edit incoming .... – Randolpho

+0

Einfache und effektive Antwort, bekam meine Stimme. :) – Noldorin

4

Ihr MemoryStream-Objekt wird ordnungsgemäß entsorgt, Sie brauchen sich darum keine Gedanken zu machen.

0

einen Blick auf den Code in Reflektor Nehmen Sie, nachdem Sie es kompilieren. Sie werden feststellen, dass der Compiler den Code neu gestaltet, um sicherzustellen, dass die Dispose im Stream aufgerufen wird.

14

using Anweisungen verhalten sich genau wie try ... finally Blöcke, so wird immer auf jedem Code Exit-Pfade ausgeführt werden. Ich glaube jedoch, dass sie den wenigen und seltenen Situationen unterliegen, in denen finally Blöcke nicht aufgerufen werden. Ein Beispiel, an das ich mich erinnern kann, ist, dass der Vordergrund-Thread beendet wird, während Hintergrund-Threads aktiv sind: Alle Threads außer dem GC sind pausiert, was bedeutet, dass finally Blöcke nicht ausgeführt werden.

Offensichtliches edit: sie verhalten sich gleich abgesehen von der Logik, die sie IDisposable Objekte behandeln können, d'oh.

Bonus Inhalt: sie gestapelt werden können (wobei Typen unterscheiden):

using (SqlConnection conn = new SqlConnection("string")) 
using (SqlCommand comm = new SqlCommand("", conn)) 
{ 

} 

Und auch kommagetrennte (wo Typen gleich sind):

using (SqlCommand comm = new SqlCommand("", conn), 
     SqlCommand comm2 = new SqlCommand("", conn)) 
{ 

}