web-dev-qa-db-ja.com

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をスキップできますか?期待どおりに動作しないStreamインプリメンテーションはありますか(CryptoStreamのように)?

そうでない場合は、次のコードが悪いだけです:

_using (StreamWriter MySW = new StreamWriter(MyStream))
{
   MySW.Write("Blah");
}
_
62
JasonRShaver

MySW.Dispose()を呼び出して、提供されていてもCloseをスキップできますか?

はい、それが目的です。

期待どおりに動作しないStream実装はありますか(CryptoStreamのような)?

オブジェクトがIDisposableを実装している場合、オブジェクト自体を適切に破棄すると想定しても安全です。

そうでない場合、それはバグになります。

そうでない場合は、次のコードが悪いだけです:

いいえ、そのコードはIDisposableを実装するオブジェクトを扱うための推奨される方法です。

より優れた情報は、 Close and Dispose-which to call? への受け入れられた回答にあります。

81
Binary Worrier

Reflectorを使用して、System.IO.Stream.Disposeは次のようになります。

public void Dispose()
{
    this.Close();
}
58
Andrew Hare

Daniel Brucknerが述べたように、DisposeとCloseは事実上同じものです。

ただし、Streamは、破棄または閉じられたときにFlush()を呼び出しません。 FileStream(およびキャッシングメカニズムを備えた他のStream)は、破棄されるときにFlush()を呼び出します。

StreamやMemoryStreamなどを拡張する場合は、必要に応じて破棄/クローズするときにFlush()の呼び出しを実装する必要があります。

21
ScottS

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
            }
        }
    }
}

それでも、私は通常、それらを廃棄する前に暗黙的にストリーム/ストリームライターを閉じます-私はそれがきれいに見えると思う。

3
Tamas Czinege

手動で閉じる必要のあるオブジェクトについては、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句のコンテキストから「ストリーム」に誤ってアクセスすることは決してできず、ファイルは常に閉じられます。

3
clemahieu

私はStreamクラスの.netソースを調べましたが、そうすることができることを示唆する次のものがありました...

    // 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
Steve Sheldon

すべての標準ストリーム(FileStream、CryptoStream)は、クローズ/破棄されるとフラッシュを試行します。 Microsoftストリームの実装にはこれを信頼できると思います。

結果として、フラッシュが失敗した場合、Close/Disposeは例外をスローできます。

実際、IIRCには、フラッシュが例外をスローした場合にファイルハンドルの解放に失敗するという点で、FileStreamの.NET 1.0実装にバグがありました。これは、Dispose(boolean)メソッドにtry/finallyブロックを追加することにより、.NET 1.1で修正されました。

3
Joe

Stream.CloseStream.Disposeの呼び出しによって実装されます。その逆も同様です。したがって、メソッドは同等です。 Stream.Closeは、ストリームを閉じるよりもストリームを閉じる方が自然に聞こえるという理由だけで存在します。

さらに、このメソッドの明示的な呼び出しを避け、代わりにusingステートメントを使用して、正しい例外処理を無料で取得するようにしてください。

2