我应该释放 XmlNodeList 吗?

6
在以下代码中,我从XmlDocument.SelectNodes()获得一个XmlNodeList作为返回值。
foreach (XmlNode node in doc.SelectNodes(xPath))
{
    // Do stuff
}

事实证明,XmlNodeList 实现了 IDisposable 接口。这是否意味着我每次想要迭代 XmlDocument.SelectNodes() 的返回值时,都应该将其放在一个局部变量中并确保它被释放(即将其放在一个 using 块中)?
像这样:
using(XmlNodeList nodes = doc.SelectNodes(xPath))
{ 
    foreach (XmlNode node in nodes)
    {
        // Do stuff
    }
}

@Chris:我看到了。但是它并没有让我清楚地知道是否应该在一般情况下调用Dispose(),正如@AgentFire所指出的那样,显然我应该这样做。但这确实使SelectNodes()不太吸引人。 - heijp06
我同意 - 不得不处理它并不好玩。就我个人而言,我认为我会忘记我曾经读过这篇文章,并继续像以前一样而不进行处理... - Chris
为什么你们不直接使用XDocument呢? - AgentFire
@AgentFire:因为这意味着要重写已在生产中运行多年的代码。如果有充分的理由,我肯定会这样做。但如果没有充分的理由,我宁愿把时间花在其他事情上。 - heijp06
请参阅C#语言规范,第8.8.4节,了解有关foreachIDisposable的信息。 - John Saunders
显示剩余3条评论
1个回答

10
系统.Xml命名空间有些奇怪。这可能是我所能使用的最友好的说法了。XmlNodeList是一个抽象类,它继承IDisposable并实现可释放模式,但除此之外没有做任何事情。
有三个内部类派生自XmlNodeList。其中一个实际上覆盖了Dispose(bool)方法,XmlElementList。该类有一个私有字段,类型为XmlElementListener。还有另一个内部类,不太清楚它的作用,但似乎它“监听”列表更改。Dispose方法(等待它)将取消订阅两个事件处理程序。
这违反了书中的所有规则,滥用IDisposable从来都是不正确的。不幸的是,你必须去调用它,否则很难解开这个问题,看看是否实例化了该侦听器,以及如果你不调用Dispose(),那些事件处理程序是否会导致你的程序出现持久泄漏。所以最好还是调用Dispose()。
.NET Framework中有很多棒极了的代码。好的代码总是需要坏的代码来突显好代码的优越性。这就是系统.Xml的工作。

哪一部分“违反了书中的所有规则”?还是全部都是? - poy
IDisposable 旨在进行任何确定性通用清理,而不仅仅是处理非托管资源。微软在一段时间前改变了他们的观点。请参见观察者模式,以获得完全相同的使用模式。这不违反任何规则。 - Cory Nelson
我最好为此调用以英语为母语的人:https://www.google.com/#q=eric+lippert+idisposable+abuse - Hans Passant
尊重Eric,他是一位优秀的开发人员,但他并不制定规则。他确实提出了一些好观点,我认为这是一个非常微妙的界限。我认为Microsoft在这里使用IDisposable处于这条线的好一侧。 - Cory Nelson
另外,你的英语非常出色:)。我本来不知道的。 - Cory Nelson
感谢您出色的回答和安慰人心的话语,关于糟糕代码的优点。我想我会像您建议的那样去实践,或者最终使用另一个API。 - heijp06

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接