Всегда ли Stream.Dispose вызывает Stream.Close(и Stream.Flush)
Если у меня есть следующая ситуация:
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()
и пропустить Close, даже если он предоставлен? Существуют ли какие-либо потоковые внедрения, которые не работают должным образом (например, CryptoStream)?
Если нет, то это следующий код:
using (StreamWriter MySW = new StreamWriter(MyStream))
{
MySW.Write("Blah");
}
Ответы
Ответ 1
Можно ли просто вызвать MySW.Dispose() и пропустите Close, хотя это при условии?
Да, вот зачем.
Есть ли какие-либо потоковые реализации которые не работают должным образом (как CryptoStream)?
Можно с уверенностью предположить, что если объект реализует IDisposable
, он будет правильно распоряжаться собой.
Если это не так, то это будет ошибкой.
Если нет, тогда это просто плохое код:
Нет, этот код является рекомендуемым способом работы с объектами, которые реализуют IDisposable
.
Более полная информация находится в принятом ответе на Close и Dispose - что вызывать?
Ответ 2
Я использовал Reflector и обнаружил, что System.IO.Stream.Dispose
выглядит так:
public void Dispose()
{
this.Close();
}
Ответ 3
Как отметил Даниэль Брукнер, Dispose and Close - это то же самое.
Однако Stream не вызывает Flush(), когда он расположен/закрыт. FileStream (и я предполагаю, что любой другой поток с механизмом кэширования) вызывает Flush() при его удалении.
Если вы расширяете Stream или MemoryStream и т.д., вам нужно будет выполнить вызов Flush(), когда он будет установлен/закрыт, если это необходимо.
Ответ 4
Оба 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
}
}
}
}
Тем не менее, я обычно неявно закрываю потоки/потоковики, прежде чем удалять их - я думаю, что он выглядит чище.
Ответ 5
Все стандартные потоки (FileStream, CryptoStream) будут пытаться скрыться при закрытии/удалении. Я думаю, вы можете положиться на это для любых реализаций потоков Microsoft.
В результате Close/Dispose может генерировать исключение, если сбой флеша.
Фактически IIRC обнаружил ошибку в реализации .NETStream FileStream в том, что он не сможет выпустить дескриптор файла, если флеш выдает исключение. Это было исправлено в .NET 1.1, добавив блок try/finally к методу Dispose (boolean).
Ответ 6
Для объектов, которые необходимо закрыть вручную, необходимо приложить все усилия для создания объекта в используемом блоке.
//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'
Таким образом, вы никогда не сможете некорректно получить доступ к "потоку" из контекста предложения use, и файл всегда закрыт.
Ответ 7
Я посмотрел в .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 where all subclasses
// should put their cleanup starting in V2.
public virtual void Close()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose()
{
Close();
}
Ответ 8
Stream.Close
реализуется вызовом Stream.Dispose
или наоборот - поэтому методы эквивалентны. Stream.Close
существует только потому, что закрытие потока звучит более естественно, чем удаление потока.
Кроме того, вы должны избегать явных вызовов этих методов и использовать оператор using
вместо этого, чтобы получить правильную обработку исключений бесплатно.