C# 为什么不鼓励我多次调用Dispose()?

C# 为什么不鼓励我多次调用Dispose()?,c#,.net,code-analysis,idisposable,using-statement,C#,.net,Code Analysis,Idisposable,Using Statement,这个问题描述了与中相同的场景,但不是关于如何修复代码,而是关于为什么首先会出现问题 以下代码: using (Stream stream = obtainStreamObject()) { using (var reader = new XmlTextReader(stream)) { //do something with XmlTextReader } } 导致调用两次Stream.Dispose()。首先,内部的using块崩溃,调用XmlText

这个问题描述了与中相同的场景,但不是关于如何修复代码,而是关于为什么首先会出现问题

以下代码:

using (Stream stream = obtainStreamObject())
{
    using (var reader = new XmlTextReader(stream))
    {
        //do something with XmlTextReader
    }
}
导致调用两次
Stream.Dispose()
。首先,内部的
using
块崩溃,调用
XmlTextReader.Dispose()
,从而导致
Stream.Dispose()
。然后外部
using
块崩溃,并再次调用
Stream.Dispose()

因此,我必须使用将
包装到
中,但不能使用
XmlTextReader
包装到
中,尽管它们都实现了
IDisposable

这将产生CA2202警告

不要多次处置对象对象对象“流”可以在方法“MethodName(无论什么)”中多次处置。为了避免生成System.ObjectDisposedException,您不应该对对象多次调用Dispose


好的,它说第二个
Dispose()
可能会产生
ObjectDisposedException
。这有什么意义?为什么我要实现
Dispose()
,以便在第二次调用它时抛出异常,而不是什么都不做

“为什么我要实现
Dispose()
,这样当第二次调用它时,它会抛出一个异常而不是什么都不做?”因为第二次实现它时,它什么都不做比不这样做更难。没有正式要求
Dispose()
可以安全地多次调用。仍然建议在已处理对象上设置
Dispose()
幂等,甚至隐式线程安全,但合同并不要求这样做。因此,在
Dispose()
之后对对象的任何调用在技术上都是不安全的——甚至是另一个
Dispose()
。在这种特殊情况下,如果对象拥有分析器不知道的其他对象,并且这些调用是无害的,那么安全(而且建议)的做法是,而不是跳转来避免它,根据@DavidG的链接,我的评论是错误的:有一个正式要求,多次调用它是安全的,因为文档:如果一个对象的
Dispose
方法被多次调用,则该对象必须忽略第一次调用之后的所有调用。如果多次调用对象的
Dispose
方法,则该对象不能抛出异常。“这一直存在于.NET 1.1中,因此不是“multiple-
Dispose
-safe”的代码被破坏,使得CA2202确实是一个糟糕的规则。(线程安全仍然是可选的。)@Jeroenmoster文档特别指出,一次性对象如果被多次处理,则不应抛出。当然,编译器不能在任何地方强制执行它,但它是
IDisposable
正式契约的一部分,尽管它是不可禁止的,但您仍应遵守该契约。