2009-06-30 10 views
142

Ich sende einen Stream zu Methoden zum Schreiben auf, und in diesen Methoden verwende ich ein binäres reader/wrtier. Wenn der Reader/Writer entsorgt wird, entweder durch using oder wenn er nicht referenziert wird, ist der Stream ebenfalls geschlossen ??Wird der Stream über den Streamreader geschlossen?

Ich würde einen BinaryReader/Writer senden, aber ich benutze auch einen StreamReader (vielleicht sollte ich das umgehen. Ich benutze das nur für GetLine und ReadLine). Dies ist ziemlich mühsam, wenn es den Strom jedes Mal schließt, wenn ein Schreiber/Leser geschlossen wird.

Antwort

166

Ja, StreamReader, StreamWriter, BinaryReader und BinaryWriter alle in der Nähe/entsorgen ihre zugrunde liegenden Ströme, wenn Sie Dispose auf sie nennen. Sie nicht entsorgen den Stream, wenn der Leser/Schreiber ist nur Müll gesammelt - Sie sollten immer den Leser/Schreiber, vorzugsweise mit einer using Anweisung entsorgen. (Tatsächlich hat keine dieser Klassen Finalizer, noch sollten sie haben.)

Persönlich bevorzuge ich auch eine using-Anweisung für den Stream. Sie können Nest using Anweisungen ohne Klammern ganz ordentlich:

using (Stream stream = ...) 
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever)) 
{ 
} 

Auch wenn die using Aussage für den Strom etwas redundant ist (es sei denn, der StreamReader Konstruktor eine Ausnahme auslöst) halte ich es für beste Praxis als dann, wenn Sie von der loswerden StreamReader und verwenden Sie den Stream direkt zu einem späteren Zeitpunkt, Sie haben bereits die richtige Entsorgungssemantik.

+2

oh gut, es geschieht nur, wenn Dispose aufrufen, nicht, wenn angeblich finalisieren. – Nefzen

+1

@Nefzen: Das ist, weil es keine Garantie gibt, welche Reihenfolge Ihre Objekte finalisiert werden. Wenn sowohl der StreamReader als auch der zugrunde liegende Stream für die Finalisierung in Frage kommen, kann der GC den Stream zuerst finalisieren - dann hätte streamreader keinen Verweis auf den Stream. Aus diesem Grund können Sie nicht verwaltete Ressourcen nur innerhalb einer endgültigen Version freigeben (z. B. schließt ein FileStream seine Windows-Dateikennung in seiner endgültigen Version). Oh, und natürlich, wenn Sie nie entsorgen, wird der Strom schließlich gesammelt (und die Datei geschlossen). Es ist nur eine sehr schlechte Übung, einen Stream nicht zu entsorgen. – JMarsch

+9

Diese Verschachtelung bewirkt, dass der VS-Code-Analyzer sich beschweren kann: 'CA2202: Microsoft.Usage: Objekt 'stream' kann in der Methode '...' mehrfach entsorgt werden. Um das Generieren einer System.ObjectDisposedException zu vermeiden, sollten Sie Dispose nicht mehrmals für ein Objekt aufrufen. Soll das einfach ignoriert werden? Ich habe bis jetzt keine Ausnahmen bekommen ... –

-3

der Strom angeordnet, entweder durch „mit“ Schlüsselwort oder explizit

27

Aufruf entsorgen Ja, es tut. Sie können dies überprüfen, indem Sie sich die Implementierung mit Reflector ansehen.

protected override void Dispose(bool disposing) 
{ 
    try 
    { 
     if ((this.Closable && disposing) && (this.stream != null)) 
     { 
      this.stream.Close(); 
     } 
    } 
    finally 
    { 
     if (this.Closable && (this.stream != null)) 
     {  
      this.stream = null;  
      this.encoding = null; 
      this.decoder = null; 
      this.byteBuffer = null; 
      this.charBuffer = null; 
      this.charPos = 0; 
      this.charLen = 0; 
      base.Dispose(disposing); 
     } 
    } 
} 
2

Ja. Der Aufruf von Dispose() on und IDisposable (was "using" bewirkt) sollte dazu führen, dass ein Objekt alle seine Ressourcen bereinigt. Dazu gehören das Löschen von Streams und das Schließen der Dateideskriptoren.

Wenn Sie in Ihrem Fall an andere Methoden übergeben möchten, müssen Sie sicherstellen, dass diese Methoden nicht in einem Verwendungsblock lesen/schreiben.

31

Dies ist ein alter, aber ich wollte etwas ähnliches tun heute und fand, dass die Dinge geändert haben. Da .net 4.5, gibt es ein leaveOpen Argument:

public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen) 

Das einzige Problem ist, dass es nicht ganz klar ist, was für die anderen Parameter einzustellen. Hier ist etwas Hilfe:

Von the msdn page für Stream Konstruktor (Stream):

Dieser Konstruktor initialisiert die Codierung UTF8Encoding, die Base Eigenschaft der Stream-Parameter verwendet wird, und die interne Puffergröße 1024 Bytes.

Das ist nur detectEncodingFromByteOrderMarks Blätter, die von the source code Beurteilung ist true

public StreamReader(Stream stream) 
     : this(stream, true) { 
} 

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks) 
     : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) { 
} 

Es wäre schön, wenn einige dieser Ausfälle ausgesetzt waren oder wenn die Argumente waren optional, so dass wir nur diejenigen angeben könnten das wollen wir.

+0

Sehr schöne Info! Ich habe noch nie von diesem neuen Parameter gehört und es macht wirklich Sinn. – julealgon

+0

Hatte den neuen Zusatz in 4.5 nicht bemerkt, danke! – TimothyP

8

Sechs Jahre zu spät, aber vielleicht könnte das jemandem helfen.

StreamReader schließt die Verbindung, wenn sie entsorgt wird. Das Verwenden von (Stream stream = ...) {...} mit StreamReader/StreamWriter kann jedoch dazu führen, dass der Stream zweimal entsorgt wird: (1) wenn das StreamReader-Objekt entsorgt wird (2) und wenn der Stream using-Block verwendet schließt. Dies führt zu einer CA2202-Warnung, wenn die Codeanalyse von VS ausgeführt wird.

Eine andere Lösung, die direkt von der Seite CA2202 übernommen wurde, ist die Verwendung eines try/finally-Blocks. Setup richtig, dies wird nur die Verbindung einmal schließen.

In der Nähe der Unterseite des CA2202, empfiehlt Microsoft die folgenden zu verwenden:

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 

statt ...

// Generates a CA2202 warning 
using (Stream stream = new FileStream("file.txt", FileMode.Open)) 
using (XmlReader reader = new XmlReader (stream)) 
{ 
    // Use the reader object... 
} 
+2

Ja, das war sehr nützlich für mich, jetzt 7 Jahre später :) – Sebastian

+0

Die Warnung wird auch in den Kommentaren der angenommenen Antwort diskutiert. Jon Skeet bietet dort einige Ratschläge an. – Marcin

Verwandte Themen