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

Mik*_*nes 42 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

mxg*_*250 21

我努力解决这个问题,发现这里的例子非常有帮助.我将发布代码以便快速查看:

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

用try/finally替换外部using语句,确保在StreamWriter中使用后将BOTH置为空,并检查以确保在处理之前它在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();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 谢谢你的MSDN链接. (2认同)

sam*_*amy 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
Run Code Online (Sandbox Code Playgroud)

要避免这种情况,只需直接创建编写器即可

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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 现在,如果新的BinaryWriter在输出流打开后抛出怎么办?谁关闭了流呢?没有人,直到终结者运行.在实践中,这并没有发生太多,在实践中,即使确实发生了最坏的后果,文件仍然保持打开状态稍长.但是,如果您的逻辑*要求*无论发生什么样的疯狂异常都会积极清理所有资源,那么此代码就不正确. (2认同)

Dis*_*ile 9

BinaryReader/BinaryWriter会在处理时为您配置底层流.您不需要明确地执行此操作.

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


Ali*_*tad 5

你的作家将永远处理你的流.


sup*_*cat 5

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