Должен ли я вызвать Close() или Dispose() для объектов потока?
классы, такие как Stream,StreamReader,StreamWriter etc реализует IDisposable интерфейс. Это означает, что мы можем назвать Dispose() метод на объектах этих классов. Они также определили public метод Close(). Теперь это смущает меня, что я должен называть, как только я закончу с объектами? А если я позвоню обоим?
мой текущий код такой:
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();
}
}
Как видите, я написал using() конструкции, которые автоматически вызывают Dispose() метод для каждого объекта. но я также называют Close() методы. Это правильно?
пожалуйста, предложите мне лучшие практики при использовании объектов потока. : -)
пример MSDN не использует using() создает, а вызов Close() способ:
это хорошо?
4 ответов:
быстрый прыжок в Reflector.NET показывает, что
Close()метод onStreamWriter- это:public override void Close() { this.Dispose(true); GC.SuppressFinalize(this); }и
StreamReader- это:public override void Close() { this.Dispose(true); }The
Dispose(bool disposing)переопределить вStreamReader- это: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; /* deleted for brevity */ base.Dispose(disposing); } } }The
StreamWriterметод похож.Итак, читая код понятно, что вы можете позвонить
Close()&Dispose()на потоки так часто, как вам нравится и в любом порядке. Это никоим образом не изменит поведение.так что все сводится к тому, или не более читабельно использовать
Dispose(),Close()и/илиusing ( ... ) { ... }.мои личные предпочтения, что
using ( ... ) { ... }всегда следует использовать, когда это возможно, поскольку это помогает вам "не работать с ножницами".но, хотя это помогает правильности, это снижает читаемость. В C# у нас уже есть множество закрывающих фигурных скобок, так как мы знаем, какой из них на самом деле выполняет закрытие потока?
так что я думаю, что это лучше всего сделать это:
using (var stream = ...) { /* code */ stream.Close(); }это не влияет на поведение кода, но это помогает читаемости.
нет, вы не должны вызывать эти методы вручную. В конце
usingблок автоматически вызывается метод Dispose, который позаботится о том, чтобы освободить неуправляемые ресурсы (по крайней мере, для стандартных классов .NET BCL, таких как streams, readers/writers,...). Таким образом, вы также можете написать свой код следующим образом: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); } } }метод Close вызывает Dispose.
в документации говорится, что эти два метода эквивалентны:
StreamReader.Закрыть: эта реализация Close вызывает метод Dispose, передающий истинное значение.
StreamWriter.Закрыть: Эта реализация Close вызывает метод Dispose, передающий истинное значение.
поток.Закрыть: этот метод вызывает метод Dispose, с указанием значения true, чтобы освободить все ресурсы.
Итак, оба они одинаково действительны:
/* Option 1 */ using (StreamWriter writer = new StreamWriter(filename)) { // do something } /* Option 2 */ StreamWriter writer = new StreamWriter(filename) try { // do something } finally { writer.Close(); }лично я бы придерживался первого варианта, так как он содержит меньше "шума".
на многих классах, которые поддерживают методы Close и Dispose, два вызова будут эквивалентны. Однако в некоторых классах можно повторно открыть объект, который был закрыт. некоторые такие классы могут поддерживать некоторые ресурсы после закрытия, чтобы разрешить повторное открытие; другие могут не поддерживать какие-либо ресурсы при закрытии, но могут установить флаг на Dispose, чтобы явно запретить повторное открытие.
контракт на IDisposable.Dispose явно требует, чтобы вызов его на объект, который никогда не будет использоваться снова, будет в худшем случае безвреден, поэтому я бы рекомендовал вызвать либо IDisposable.Dispose или метод, называемый Dispose для каждого объекта IDisposable, независимо от того, вызывает ли он также Close.
Comments