Выполняет Stream.Dispose всегда вызывает Stream.Закрыть (и Stream.Сбросить)
Вопрос
Если у меня возникнет следующая ситуация:
StreamWriter MySW = null;
try
{
Stream MyStream = new FileStream("asdf.txt");
MySW = new StreamWriter(MyStream);
MySW.Write("blah");
}
finally
{
if (MySW != null)
{
MySW.Flush();
MySW.Close();
MySW.Dispose();
}
}
Могу я просто позвонить MySW.Dispose()
и пропустить Закрытие, даже если оно предусмотрено?Существуют ли какие-либо реализации потока, которые работают не так, как ожидалось (например, CryptoStream)?
Если нет, то является ли следующий просто плохим кодом:
using (StreamWriter MySW = new StreamWriter(MyStream))
{
MySW.Write("Blah");
}
Решение
Могу ли я просто вызвать MySW.Dispose() и пропустить закрытие, даже если оно предусмотрено ?
Да, именно для этого он и предназначен.
Существуют ли какие-либо реализации Stream , которые работают не так, как ожидалось (например, CryptoStream)?
Можно с уверенностью предположить, что если объект реализует IDisposable
, он будет распоряжаться собой должным образом.
Если это не так, то это было бы ошибкой.
Если нет, то является ли следующее просто плохим код:
Нет, этот код является рекомендуемым способом работы с объектами, которые реализуют IDisposable
.
Более подробная информация содержится в принятом ответе на Закрыть и утилизировать - что вызывать?
Другие советы
Я использовал Reflector и обнаружил, что System.IO.Stream.Dispose
выглядит примерно так:
public void Dispose()
{
this.Close();
}
Как упоминал Дэниел Брукнер, Dispose и Close - это фактически одно и то же.
Однако Stream НЕ вызывает Flush(), когда он удален / закрыт.FileStream (и я предполагаю, что любой другой поток с механизмом кэширования) вызывает Flush() при удалении.
Если вы расширяете Stream, или MemoryStream и т.д.вам нужно будет реализовать вызов Flush() при удалении / закрытии, если это необходимо.
Оба StreamWriter.Dispose() и Stream.Dispose() освобождают все ресурсы, удерживаемые объектами.Оба они закрывают базовый поток.
Исходный код Stream.Dispose() (обратите внимание, что это детали реализации, поэтому не полагайтесь на это):
public void Dispose()
{
this.Close();
}
StreamWriter.Dispose() (то же, что и с Stream.Dispose()):
protected override void Dispose(bool disposing)
{
try
{
// Not relevant things
}
finally
{
if (this.Closable && (this.stream != null))
{
try
{
if (disposing)
{
this.stream.Close();
}
}
finally
{
// Not relevant things
}
}
}
}
Тем не менее, я обычно неявно закрываю streams / streamwriters перед их удалением - я думаю, это выглядит чище.
Все стандартные потоки (FileStream, CryptoStream) будут пытаться сбросить данные при закрытии / удалении.Я думаю, вы можете положиться на это при любых реализациях Microsoft stream.
В результате Close /Dispose может выдать исключение, если сброс завершится неудачей.
На самом деле, IIRC в реализации FileStream .NET 1.0 была ошибка, заключающаяся в том, что она не смогла бы освободить дескриптор файла, если бы сброс вызывал исключение.Это было исправлено в .NET 1.1 путем добавления блока try / finally к методу Dispose(boolean).
Для объектов, которые необходимо закрыть вручную, следует приложить все усилия для создания объекта в блоке using.
//Cannot access 'stream'
using (FileStream stream = File.Open ("c:\\test.bin"))
{
//Do work on 'stream'
} // 'stream' is closed and disposed of even if there is an exception escaping this block
// Cannot access 'stream'
Таким образом, никто никогда не сможет неправильно получить доступ к 'stream' вне контекста предложения using, и файл всегда будет закрыт.
Я посмотрел в исходном коде .net для класса Stream , в нем было следующее, что наводит на мысль, что да, вы можете...
// Stream used to require that all cleanup logic went into Close(),
// which was thought up before we invented IDisposable. However, we
// need to follow the IDisposable pattern so that users can write
// sensible subclasses without needing to inspect all their base
// classes, and without worrying about version brittleness, from a
// base class switching to the Dispose pattern. We're moving
// Stream to the Dispose(bool) pattern - that's where all subclasses
// should put their cleanup starting in V2.
public virtual void Close()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose()
{
Close();
}
Stream.Close
реализуется вызовом к Stream.Dispose
или наоборот - таким образом, методы эквивалентны. Stream.Close
существует только потому, что закрытие потока звучит более естественно, чем удаление потока.
Кроме того, вам следует стараться избегать явных вызовов этих методов и использовать using
заявление вместо этого, чтобы бесплатно получить правильную обработку исключений.