简体   繁体   English

“对象可以被多次处理”错误

[英]“Object can be disposed of more than once” error

When I run code analysis on the following chunk of code I get this message:当我对以下代码块运行代码分析时,我收到此消息:

Object 'stream' can be disposed more than once in method 'upload.Page_Load(object, EventArgs)'.对象 'stream' 可以在方法 'upload.Page_Load(object, EventArgs)' 中多次处理。 To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.为避免生成 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);
    }
}

I don't understand why it might be called twice, and how to fix it to eliminate the error.我不明白为什么它可能会被调用两次,以及如何修复它以消除错误。 Any help?有什么帮助吗?

I struggled with this problem and found the example here to be very helpful.我在这个问题上苦苦挣扎,发现这里的例子非常有帮助。 I'll post the code for a quick view:我将发布代码以便快速查看:

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

Replace the outer using statement with a try/finally making sure to BOTH null the stream after using it in StreamWriter AND check to make sure it is not null in the finally before disposing.用 try/finally 替换外部 using 语句,确保在 StreamWriter 中使用流后将其设为空,并在处理之前检查以确保它在 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();
}

Doing this cleared up my errors.这样做清除了我的错误。

To illustrate, let's edit your code为了说明,让我们编辑您的代码

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

To avoid this, just create the writer directly为避免这种情况,只需直接创建编写器

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 : to take into account what Eric Lippert is saying, there could indeed be a moment when the stream is only released by the finalizer if BinaryWriter throws an exception. edit :考虑到 Eric Lippert 所说的内容,如果 BinaryWriter 抛出异常,则确实可能有一段时间仅由终结器释放流。 According to the BinaryWriter code, that could occur in three cases根据 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
  • if you didn't specify an output, ie if stream is null.如果您没有指定输出,即如果流为空。 That shouldn't be a problem since a null stream means no resources to dispose of :)这应该不是问题,因为空流意味着没有要处理的资源:)
  • if you didn't specify an encoding.如果您没有指定编码。 since we don't use the constructor form where the encoding is specified, there should be no problem here either (i didn't look into the encoding contructor too much, but an invalid codepage can throw)由于我们没有使用指定编码的构造函数形式,所以这里也应该没有问题(我没有过多研究编码构造函数,但可能会抛出无效的代码页)
    • if you don't pass a writable stream.如果您不传递可写流。 That should be caught quite quickly during development...这应该在开发过程中很快被发现......

Anyway, good point, hence the edit :)无论如何,好点,因此编辑:)

The BinaryReader/BinaryWriter will dispose the underlying stream for you when it disposes. BinaryReader/BinaryWriter 会在处理时为您处理底层流。 You don't need to do it explicitly.您不需要明确地这样做。

To fix it you can remove the using around the Stream itself.要修复它,您可以删除 Stream 本身周围的 using。

您的作者将始终处理您的流。

A proper implementation of Dispose is explicitly required not to care if it's been called more than once on the same object.明确要求 Dispose 的正确实现不关心它是否在同一个对象上被多次调用。 While multiple calls to Dispose are sometimes indicative of logic problems or code which could be better written, the only way I would improve the original posted code would be to convince Microsoft to add an option to BinaryReader and BinaryWriter instructing them not to dispose their passed-in stream (and then use that option).虽然对 Dispose 的多次调用有时表明存在逻辑问题或可以更好地编写代码,但我改进原始发布代码的唯一方法是说服 Microsoft 向 BinaryReader 和 BinaryWriter 添加一个选项,指示他们不要处理传递的 -在流中(然后使用该选项)。 Otherwise, the code required to ensure the file gets closed even if the reader or writer throws in its constructor would be sufficiently ugly that simply letting the file get disposed more than once would seem cleaner.否则,即使读取器或写入器抛出其构造函数,确保文件关闭所需的代码也会非常丑陋,以至于简单地多次处理文件看起来会更干净。

Suppress CA2202 whenever you are sure that the object in question handles multiple Dispose calls correctly and that your control flow is impeccably readable.每当您确定相关对象正确处理多个Dispose调用并且您的控制流具有无可挑剔的可读性时,就禁止 CA2202。 BCL objects generally implement Dispose correctly. BCL 对象通常正确实现Dispose Streams are famous for that.流因此而闻名。

But don't necessarily trust third party or your own streams if you don't have unit tests probing that scenario yet.但是,如果您还没有进行单元测试来探索该场景,则不一定要信任第三方或您自己的流。 An API which returns a Stream may be returning a fragile subclass.返回Stream的 API 可能返回脆弱的子类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM