Всегда ли 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() и пропустить закрытие, даже если оно предусмотрено? Существуют ли какие-либо имплементации Stream, которые не работают должным образом (например, CryptoStream)?

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

using (StreamWriter MySW = new StreamWriter(MyStream))
{
   MySW.Write("Blah");
}

person JasonRShaver    schedule 26.05.2009    source источник
comment
почему вы используете свои локальные переменные с заглавной буквы? Бедная голова болит :(   -  person mpen    schedule 22.07.2010
comment
Я пришел к соглашению, что локальная область видимости заглавными буквами и меньше для params (NewOrderLineItem vs newOrderLineItem). Просто то, к чему я привык =)   -  person JasonRShaver    schedule 22.07.2010
comment
возможный дубликат Close and Dispose - что вызывать?   -  person Binary Worrier    schedule 27.11.2013
comment
@BinaryWorrier, другой вопрос более общий и охватывает множество разных случаев. SqlConnection показывает некоторые различия между Close и Dispose, которых у Stream нет.   -  person Frédéric    schedule 25.09.2015


Ответы (8)


Могу ли я просто вызвать MySW.Dispose () и пропустить закрытие, даже если оно предусмотрено?

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

Существуют ли какие-либо реализации Stream, которые не работают должным образом (например, CryptoStream)?

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

Если этого не произойдет, то это будет ошибкой.

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

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

Более полезная информация содержится в принятом ответе на вопрос Close and Dispose - что вызывать?

person Binary Worrier    schedule 26.05.2009

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

public void Dispose()
{
    this.Close();
}
person Andrew Hare    schedule 26.05.2009

Как сказал Дэниел Брукнер, Dispose и Close - это одно и то же.

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

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

person ScottS    schedule 18.06.2009
comment
Я изучал это недавно, и если вы расширяете MemoryStream, вам, вероятно, не нужно беспокоиться о промывке. Взгляд на реализацию Flush для MemoryStream показывает, что на самом деле это не работает, на самом деле в документации указано Overrides Flush, поэтому никакие действия не выполняются. - person Mike Goatly; 23.06.2011
comment
@Mike, если поток записывает непосредственно в память без буферизации, тогда сброс не требуется, если поток вводит некоторую буферизацию поверх небуферизованного в противном случае типа потока, потребуется вызов сброса. - person ScottS; 23.06.2011
comment
С этим не поспоришь - извини, что раскопал пост двухлетней давности! :) - person Mike Goatly; 24.06.2011

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

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

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

person Joe    schedule 26.05.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
            }
        }
    }
}

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

person Tamas Czinege    schedule 26.05.2009

Для объектов, которые необходимо закрыть вручную, следует приложить все усилия для создания объекта в блоке 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' 

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

person clemahieu    schedule 19.06.2009

Я просмотрел источник .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(); 
    } 
person Steve Sheldon    schedule 15.02.2012

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

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

person Daniel Brückner    schedule 26.05.2009