【问题标题】:If an exception is thrown from IEnumerator<T>.MoveNext() or .Current, must it be still be disposed?如果从 IEnumerator<T>.MoveNext() 或 .Current 引发异常,是否还必须处理它?
【发布时间】:2010-12-11 09:44:46
【问题描述】:

直觉上我认为是的,但我不确定是否有一些我不知道的约定。

【问题讨论】:

    标签: c# exception dispose idisposable ienumerator


    【解决方案1】:

    由于我们不知道具体实现是什么,唯一安全的答案是“是”。

    然而,直接使用IEnumerator 是非常罕见的——foreach 更常见。对于通用 IEnumerator&lt;T&gt;,您可以使用 using 语句:

    using(var iter = obj.GetEnumerator()) {
        ...
    }
    

    即使没有通用版本,你也可以作弊:

    IEnumerator iter = obj.GetEnumerator();
    using(iter as IDisposable) {
        ...
    }
    

    如果它是 IDisposable 会释放 iter

    【讨论】:

      【解决方案2】:

      没有一次性物品必须被丢弃,永远。[1]

      但他们应该是。由于using 块使用finally 子句进行处理,并且无论using 块是正常退出还是通过异常退出,都会执行此操作,因此默认情况下即使遇到异常也会进行处理。


      [1] 我想可能会有一个错误的实现,其中持有非托管资源并且没有终结器,但正确的操作是实现终结器。

      【讨论】:

      • IDisposable 对象可能是一个连接、一个文件、一个事务等(即可以竞争的东西;注意这可能在一个迭代器块内,所以适用于IEnumerator case) - 那么等待一个非确定性的 GC 可能会非常糟糕。 IMO“必须”非常合适。
      • @Marc:必须意味着强制,不这样做本质上是一个错误。应该意味着:你需要一个很好的理由不这样做。并且框架设计指南(第 9.4 节)中的评论不同意:[Joe Duffy]“当你完成对象时,你应该尽你所能调用 Dispose。但是如果所有权变得棘手(因为对象是从多个地方引用或共享的)例如,跨线程),忽略调用 Dispose 不会造成任何伤害。”。也就是说,我在本地假设“无害”,很明显,如果资源被锁定,你就会遇到问题,但情况并非总是如此。
      • @Richard - 由于他无法预测实施,他能说的最好的就是它“应该”没有害处;和“应该”相乘带来了很多不可预测性。我明白你在在说什么,但就个人而言我宁愿看到尽可能强烈地加强“处置它”的论点。但论证充分,有效 (+1),但可以说会误导初学者,希望自己变得懒惰。
      • Winforms 的 Control.Dispose() 是一个例子,我知道不处理会导致不可恢复的泄漏。这就是麻烦,没有黄金法则。
      • @Richard:在许多情况下,确保有效清理未处置的 IDisposable 是不切实际的;确实,这里提到的 IEnumerable 情况就是其中之一。作为一个简单的场景,假设一个 IEnumerable 需要在集合即将被修改时接收通知(例如,因为使用写时复制实现了惰性快照语义)。如果集合是长期存在的,并且经常被枚举但从不修改,那么每个枚举器都将与集合一样长。重大内存泄漏。
      猜你喜欢
      • 2014-09-05
      • 2014-09-15
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 2012-09-24
      • 2022-09-29
      相关资源
      最近更新 更多