C# / .NET编译器为何不警告Dispose()方法?

6

我今天在写一些IDisposable代码时想到了这个问题。

对于开发人员来说,直接调用Dispose()是好的实践,或者如果对象的生命周期允许,可以使用using结构。

我们需要担心的唯一情况是那些由于我们代码的机制而无法使用using的情况。但是,我们应该在某个时候调用这些对象的Dispose()

考虑到C#编译器知道对象实现了IDisposable,它理论上也可以知道Dispose()从未在其上调用过(它已经是一个非常聪明的编译器!)。它可能不知道程序员应该何时这样做的语义,但它可以作为一个很好的提醒,即因为它从未被用于using结构中,并且没有直接调用实现IDisposable的任何对象的Dispose()方法。

这是什么原因,还是有想要走这条路的想法吗?

3个回答

2
它可以在某些简单情况下确定Dispose永远不会被调用。但仅基于代码的静态分析无法确定所有创建的实例都将被处理。即使是非常简单的代码,也可能导致对象未被处理而难以估计。更糟糕的是,并非所有的IDisposable对象实例都需要被处理。有很多原因造成这种情况。有些对象实现了IDisposable接口,但只有一部分实例实际上在实现中执行了任何操作。例如,IEnumerator<T>就是一个很好的例子,其中大量的实现在被处理时什么也不做,但有些实现会执行某些操作。如果你知道你所拥有的具体实现在处理时不需要执行任何操作,则可以不必担心;否则,您需要确保调用Dispose方法。还有一些类型,例如Task,几乎不需要被处理(请参见Do I need to dispose of Tasks?)。在绝大多数情况下,您不需要对其进行处理,在代码中不必要地添加using块或无用的释放调用会降低可读性。

谢谢您。这是一个非常好的观点,实际上提供了一个真正的原因,解释为什么已经很聪明的编译器不会这样做。正如pstrjds所指出的那样,静态分析是更好的方法,因此编译器不会在每次编译时打扰程序员,因为代码中的所有300个List<T>引用都没有被开发人员显式地释放。 - Moo-Juice
几乎所有的 IDisposable 对象实例都应该被处理,仅一次;唯一不需要处理的是像 StreamReader 这样设计不良的类,它们假设一旦它们接收到对象的引用,提供该引用的人将不再需要该对象。主要的混乱问题源于即使可能存在许多对一个对象的引用,只有最后一个使用该对象的用户应该 Dispose 它。 - supercat
3
我不喜欢这种观念:即使在相对容易的情况下,当前实现不执行任何操作的类也不需要打扰调用“Dispose”方法。有些情况下,在适当的时候确保对象被释放可能会很困难,但如果知道该对象的特定类可以安全地放弃而不需要释放,那么这种放弃可能是合理的,只要明确注释了意图。没有进行处理就放弃一个对象的代码依赖于该对象的实现细节,我喜欢尽量减少这样的依赖。 - supercat

2
关于IDisposable的主要规则是“最后一个离开房间的人,请关灯”。大多数.NET语言设计中的一个主要缺陷是没有一般性的语法(甚至没有属性标记)来指示持有特定变量的代码或持有特定字段的类是否会:
  1. 始终是最后一个离开房间的人
  2. 永远不是最后一个离开房间的人
  3. 有时可能是最后一个离开房间的人,并且在运行时很容易知道它是否会是最后一个离开房间的人(例如,因为给它引用的人告诉了它)。
  4. 可能是最后一个离开房间的人,但在离开房间之前不知道它是否会成为最后一个。
如果语言具有区分这些情况的语法,则编译器可以简单地确保那些知道它们将成为最后一个离开房间的东西关掉灯,而那些永远不会成为最后一个离开房间的东西不关灯。如果框架包括编译器已知的包装类型,则编译器或框架可以促进第三和第四种情况。通常,传统的引用计数机制不是确定对象是否不再需要的主要机制,因为每次复制或销毁引用时都需要处理器互锁,即使副本的持有者知道它不会成为“最后一个离开房间的人”,但是引用计数的变化通常是处理情况#4 [仅当原始和副本的持有者都认为自己可能是最后的所有者时,复制引用才应增加计数器,并且如果在创建该副本时已增加引用,则仅当销毁引用的副本时才应减少计数器]的最便宜和最实用的方法。
在没有指示特定引用应被视为“房间中的最后一个”的约定的情况下,编译器无法知道持有该引用的持有者是否应“关灯”(即调用Dispose)。VB.NET和C#都有一个特殊的using语法,适用于持有变量的持有者知道它将是最后一个离开房间的情况,但除此之外,如果编译器不理解它们,它们不能真正要求清理事物。 C ++ / CLI确实具有更通用的语法,但不幸的是它有许多使用限制。

1
代码分析规则将检测到此问题。根据您使用的VS版本,您可以使用FXCop或内置的分析规则。需要在编译后对代码进行静态分析。

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