“对象可以不止一次处理”错误

时间:2010-10-20 22:04:13

标签: c# dispose

当我对以下代码块运行代码分析时,我得到以下消息:

对象'stream'可以在方法'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);
    }
}

我不明白为什么它可能会被调用两次,以及如何修复它以消除错误。有什么帮助吗?

6 个答案:

答案 0 :(得分:19)

我努力解决这个问题,并发现示例here非常有用。我将发布代码以便快速查看:

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

使用try / finally替换外部using语句,确保在StreamWriter中使用后将BOTH置为空,并在处理之前检查以确保它在finally中为空。

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

这样做可以解决我的错误。

答案 1 :(得分:13)

为了说明,让我们编辑你的代码

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代码,可能会出现三种情况

  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
  • 如果未指定输出,即stream是否为null。这应该不是问题,因为空流意味着没有资源可以处置:)
  • 如果您未指定编码。因为我们不使用指定编码的构造函数表单,所以这里也应该没有问题(我没有太多地查看编码构造函数,但是可能会抛出无效的代码页)
    • 如果您没有传递可写流。这应该在开发过程中很快发现......

无论如何,好点,因此编辑:)

答案 2 :(得分:8)

BinaryReader / BinaryWriter会在处理时为您配置基础流。您无需明确地执行此操作。

要修复它,您可以删除Stream本身的使用。

答案 3 :(得分:5)

您的作家将始终处理您的信息流。

答案 4 :(得分:5)

明确要求正确实现Dispose,不要在意它是否在同一个对象上被多次调用。虽然对Dispose的多次调用有时表示逻辑问题或代码可以更好地编写,但我改进原始发布代码的唯一方法是说服Microsoft向BinaryReader和BinaryWriter添加一个选项,指示他们不要处理他们的传递 - 在流中(然后使用该选项)。否则,即使读者或作者抛出其构造函数,确保文件被关闭所需的代码也会非常难看,只是让文件被多次处理似乎更清晰。

答案 5 :(得分:0)

只要您确定相关对象正确处理多个 Dispose 调用并且您的控制流具有无可挑剔的可读性,就禁止 CA2202。 BCL 对象通常正确实现 Dispose。流因此而闻名。

但是,如果您还没有进行单元测试来探索该场景,则不一定要信任第三方或您自己的流。返回 Stream 的 API 可能返回脆弱的子类。