Всегда ли Stream.Dispose вызывать Stream.Close (и Stream.Flush) - PullRequest
62 голосов
/ 26 мая 2009

Если у меня следующая ситуация:

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");
}

Ответы [ 8 ]

81 голосов
/ 26 мая 2009

Могу ли я просто позвонить MySW.Dispose () и пропустить Закрыть, хотя это при условии,

Да, вот для чего.

Есть ли реализации Stream это не работает, как ожидалось (как CryptoStream)

Можно с уверенностью предположить, что если объект реализует IDisposable, он будет правильно распоряжаться собой.

Если это не так, то это будет ошибка.

Если нет, то это просто плохо код:

Нет, этот код является рекомендуемым способом работы с объектами, которые реализуют IDisposable.

Более подробная информация содержится в принятом ответе на Закрыть и утилизировать - куда звонить?

58 голосов
/ 26 мая 2009

Я использовал Reflector и обнаружил, что System.IO.Stream.Dispose выглядит так:

public void Dispose()
{
    this.Close();
}
21 голосов
/ 19 июня 2009

Как упоминал Даниэль Брукнер, «Распоряжение и закрытие» - это одно и то же.

Однако Stream НЕ вызывает Flush (), когда он удаляется / закрывается. FileStream (и я предполагаю, что любой другой поток с механизмом кэширования) вызывает Flush () при утилизации.

Если вы расширяете Stream или MemoryStream и т. Д., Вам нужно будет реализовать вызов Flush () при его удалении / закрытии, если это необходимо.

3 голосов
/ 16 февраля 2012

Я искал в источнике .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(); 
    } 
3 голосов
/ 19 июня 2009

Для объектов, которые необходимо закрыть вручную, необходимо приложить все усилия для создания объекта в блоке использования.

//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' 

Таким образом, невозможно получить неправильный доступ к «потоку» вне контекста предложения using, и файл всегда будет закрыт.

3 голосов
/ 26 мая 2009

Все стандартные потоки (FileStream, CryptoStream) будут пытаться очистить при закрытии / удалении. Я думаю, что вы можете положиться на это для любых реализаций потоков Microsoft.

В результате Close / Dispose может вызвать исключение, если сбой завершается неудачей.

На самом деле в IIRC была ошибка в реализации .NET 1.0 FileStream, заключающаяся в том, что он не смог освободить дескриптор файла, если сброс завершит исключение. Это было исправлено в .NET 1.1 путем добавления блока try / finally к методу Dispose (логический).

3 голосов
/ 26 мая 2009

Оба 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
            }
        }
    }
}

Тем не менее, я обычно неявно закрываю потоки / потоковые записи перед их удалением - думаю, это выглядит чище.

2 голосов
/ 26 мая 2009

Stream.Close реализуется путем вызова Stream.Dispose или наоборот - поэтому методы эквивалентны. Stream.Close существует только потому, что закрытие потока звучит более естественно, чем удаление потока.

Кроме того, вам следует избегать явных обращений к этим методам и вместо этого использовать оператор using, чтобы получить правильную обработку исключений бесплатно.

...