web-dev-qa-db-ja.com

「オブジェクトは複数回廃棄できます」エラー

次のコードチャンクでコード分析を実行すると、次のメッセージが表示されます。

オブジェクト「ストリーム」は、メソッド「upload.Page_Load(object、EventArgs)」で複数回破棄できます。 System.ObjectDisposedExceptionの生成を回避するには、オブジェクトに対してDisposeを複数回呼び出さないでください。

using(var stream = File.Open(newFilename, FileMode.CreateNew))
using(var reader = new BinaryReader(file.InputStream))
using(var writer = new BinaryWriter(stream))
{
    var chunk = new byte[ChunkSize];
    Int32 count;
    while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
    {
        writer.Write(chunk, 0, count);
    }
}

なぜ2回呼び出されるのか、エラーを解消するために修正する方法がわかりません。何か助けはありますか?

44
Mike Jones

私はこの問題に苦労し、例 ここ が非常に役立つことがわかりました。簡単に確認できるようにコードを投稿します。

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        // Use the writer object...
    }
}

外側のusingステートメントをtry/finalに置き換えて、StreamWriterで使用した後にストリームをnullにすることと、破棄する前にfinallyでnullでないことを確認することの両方を確認してください。

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

これを行うことで私のエラーが解消されました。

22
mxgg250

説明のために、コードを編集してみましょう

using(var stream = File.Open(newFilename, FileMode.CreateNew))
{
    using(var reader = new BinaryReader(file.InputStream))
    {
        using(var writer = new BinaryWriter(stream))
        {
            var chunk = new byte[ChunkSize];
            Int32 count;
            while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
            {
                writer.Write(chunk, 0, count);
            }
        } // here we dispose of writer, which disposes of stream
    } // here we dispose of reader
} // here we dispose a stream, which was already disposed of by writer

これを回避するには、ライターを直接作成するだけです

using(var reader = new BinaryReader(file.InputStream))
    {
        using(var writer = new BinaryWriter( File.Open(newFilename, FileMode.CreateNew)))
        {
            var chunk = new byte[ChunkSize];
            Int32 count;
            while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
            {
                writer.Write(chunk, 0, count);
            }
        } // here we dispose of writer, which disposes of its inner stream
    } // here we dispose of reader

edit:Eric Lippertが言っていることを考慮に入れると、BinaryWriterが例外をスローした場合にのみ、ストリームがファイナライザーによってリリースされる瞬間が実際に存在する可能性があります。 BinaryWriterコードによると、これは3つのケースで発生する可能性があります

  If (output Is Nothing) Then
        Throw New ArgumentNullException("output")
    End If
    If (encoding Is Nothing) Then
        Throw New ArgumentNullException("encoding")
    End If
    If Not output.CanWrite Then
        Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"))
    End If
  • 出力を指定しなかった場合、つまりストリームがnullの場合。ヌルストリームは破棄するリソースがないことを意味するため、これは問題にはなりません:)
  • エンコーディングを指定しなかった場合。エンコーディングが指定されているコンストラクタフォームを使用しないため、ここでも問題はありません(エンコーディングコンストラクタをあまり調べませんでしたが、無効なコードページがスローされる可能性があります)
    • 書き込み可能なストリームを渡さない場合。それは開発中に非常に迅速にキャッチされるはずです...

とにかく、良い点、したがって編集:)

13
samy

BinaryReader/BinaryWriterは、基になるストリームを破棄するときに破棄します。明示的に行う必要はありません。

これを修正するには、ストリーム自体の使用を削除します。

9
Dismissile

Disposeの適切な実装は、同じオブジェクトで複数回呼び出されても気にしないように明示的に要求されます。 Disposeの複数の呼び出しは、ロジックの問題やより適切に記述できるコードを示している場合がありますが、元の投稿されたコードを改善する唯一の方法は、渡されたコードを破棄しないように指示するオプションをBinaryReaderとBinaryWriterに追加するようにMicrosoftを説得することです。ストリーム内(そしてそのオプションを使用)。そうしないと、リーダーまたはライターがコンストラクターをスローした場合でもファイルを確実に閉じるために必要なコードが十分に醜くなり、ファイルを複数回破棄するだけでクリーンに見えるようになります。

5
supercat

あなたのライターは常にあなたのストリームを破棄します。

5
Aliostad