Klassen wie Stream
, StreamReader
, StreamWriter
usw. Geräte - IDisposable
Schnittstelle. Das heißt, wir können anrufenDispose()
Methoden für Objekte dieser Klassen . Sie haben auch eine public
Methode namens aufgerufen Close()
. Das verwirrt mich, was soll ich nennen, wenn ich mit Objekten fertig bin? Was ist, wenn ich beide anrufe?
Mein aktueller Code lautet:
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
using (StreamWriter writer = new StreamWriter(filename))
{
int chunkSize = 1024;
while (!reader.EndOfStream)
{
char[] buffer = new char[chunkSize];
int count = reader.Read(buffer, 0, chunkSize);
if (count != 0)
{
writer.Write(buffer, 0, count);
}
}
writer.Close();
}
reader.Close();
}
}
Wie Sie sehen, habe ich using()
Konstrukte geschrieben , die automatisch aufrufenDispose()
Methoden für jedes Objekt . Ich nenne aber auch Close()
Methoden. Ist es richtig?
Bitte schlagen Sie mir die Best Practices für die Verwendung von Stream-Objekten vor. :-)
Das MSDN-Beispiel verwendet keine using()
Konstrukte und ruft die Close()
Methode auf:
Ist es gut?
using (MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream()) { }
. Ich meine so, wo Sie den Typ neu definieren können:using (MemoryStream ms = new MemoryStream()) using (FileStream fs = File.OpenRead("c:\\file.txt")) { }
Antworten:
Ein kurzer Sprung in Reflector.NET zeigt, dass die
Close()
Methode aktiviertStreamWriter
ist:Und
StreamReader
ist:Die
Dispose(bool disposing)
Überschreibung inStreamReader
ist:Die
StreamWriter
Methode ist ähnlich.Also, den Code zu lesen ist es klar, dass , dass Sie anrufen können
Close()
undDispose()
auf Ströme , so oft , wie Sie möchten und in beliebiger Reihenfolge. Es wird das Verhalten in keiner Weise ändern.Es kommt also darauf an, ob es besser lesbar
Dispose()
istClose()
und / undusing ( ... ) { ... }
.Meine persönliche Präferenz ist, dass
using ( ... ) { ... }
immer verwendet werden sollte, wenn es möglich ist, da es Ihnen hilft, "nicht mit der Schere zu laufen".Dies hilft zwar bei der Korrektheit, verringert jedoch die Lesbarkeit. In C # gibt es bereits eine Vielzahl von schließenden geschweiften Klammern. Woher wissen wir also, welche tatsächlich das Schließen des Streams ausführt?
Ich denke, es ist am besten, dies zu tun:
Es hat keinen Einfluss auf das Verhalten des Codes, verbessert jedoch die Lesbarkeit.
quelle
Close()
Anruf nicht einverstanden . Wenn jemand, der weniger erfahren ist, sich den Code ansieht und nichts davon weißusing
, wird er: 1) ihn nachschlagen und lernen oder 2) blind einenClose()
manuell hinzufügen . Wenn er 2) auswählt, sieht vielleicht ein anderer Entwickler den RedundantenClose()
und weist den weniger erfahrenen Entwickler an, anstatt zu "kichern" . Ich bin nicht dafür, unerfahrenen Entwicklern das Leben schwer zu machen, aber ich bin dafür, sie zu erfahrenen Entwicklern zu machen.Nein, Sie sollten diese Methoden nicht manuell aufrufen. Am Ende des
using
BlocksDispose()
wird automatisch die Methode aufgerufen, die dafür sorgt, dass nicht verwaltete Ressourcen freigegeben werden (zumindest für Standard-.NET-BCL-Klassen wie Streams, Reader / Writer, ...). Sie können Ihren Code also auch folgendermaßen schreiben:Die
Close()
Methode ruft aufDispose()
.quelle
using
der Erste sein müssen,responseStream
da dies von dem umhülltreader
wird, der sicherstellt, dass es geschlossen ist, wenn der Leser entsorgt wird. +1 trotzdemThe Close method calls Dispose.
... und im Rest Ihres Beitrags implizieren Sie, dassDispose()
dies anrufen würdeClose()
, ich sollte letzteres nicht manuell anrufen. Wollen Sie damit sagen, dass sie sich gegenseitig anrufen?using
Block verwenden können. Ich implementiere eine Klasse, die von Zeit zu Zeit schreibt und daher nicht kann.using
(oder erneut das Dispose-Muster verwenden können).Die Dokumentation besagt, dass diese beiden Methoden gleichwertig sind:
Beide sind also gleichermaßen gültig:
Persönlich würde ich bei der ersten Option bleiben, da sie weniger "Rauschen" enthält.
quelle
In vielen Klassen, die beide
Close()
undDispose()
Methoden unterstützen, wären die beiden Aufrufe gleichwertig. In einigen Klassen ist es jedoch möglich, ein geschlossenes Objekt erneut zu öffnen. Einige dieser Klassen halten möglicherweise einige Ressourcen nach einem Abschluss am Leben, um ein erneutes Öffnen zu ermöglichen. Andere halten möglicherweise keine Ressourcen am LebenClose()
, setzen jedoch möglicherweise ein Flag,Dispose()
um das erneute Öffnen explizit zu verbieten.Der Vertrag für
IDisposable.Dispose
verlangt ausdrücklich, dass das Aufrufen eines Objekts, das nie wieder verwendet wird, im schlimmsten Fall harmlos ist. Daher würde ich empfehlen, entwederIDisposable.Dispose
oder eine Methode aufzurufen , dieDispose()
für jedesIDisposable
Objekt aufgerufen wird , unabhängig davon, ob eines auch aufgerufen wird oder nichtClose()
.quelle
Dies ist eine alte Frage, aber Sie können jetzt mit Anweisungen schreiben, ohne jede einzelne blockieren zu müssen. Sie werden in umgekehrter Reihenfolge entsorgt, wenn der enthaltende Block fertig ist.
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using
quelle