Всегда ли 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 вместо этого, чтобы получить правильную обработку исключений бесплатно.