Dispose vs. Iterator blocks

时间:2014-03-05 15:00:20

标签: c# ienumerable dispose yield-return ienumerator

这两个问题几乎可以回答我自己的问题,但并不完全。考虑这是对这些问题的后续问题。

我理解,当枚举器完成后,foreach循环将Dispose

我的问题是:

如果有问题的枚举器实际上是GetEnumerator()/yield类的ac#iterator块(即IEnumerable<T>),它本身实现了IDisposable,我可以确定对象本身是否会被处置?或者我是否需要在GetEnumerator()/MoveNext()/Current块内明确调用using

编辑: This snippet演示@ JonSkeet的答案。

编辑#2: This snippet,基于@ JonSkeet的评论,展示了理想的用法。迭代器块负责所需资源的生命周期,而不是可枚举对象本身。这样,如果需要,可以多次枚举枚举 - 每个枚举都有自己的资源可供使用。

2 个答案:

答案 0 :(得分:6)

无论迭代器的实现如何,

foreach都会在迭代器上调用Dispose。如果它是使用迭代器块创建的并不重要,它的Dispose方法被调用。

这就是界面的重点,例如IDisposable。您不需要关注底层实现是什么。 总是处理所有内容。他们选择用这个电话做什么取决于他们。

至于迭代器块生成的IEnumerable<T>(不是IEnumerator<T>),永远不会实现IDisposable ,因此不能< / em>被处置。如果您有一个实现IEnumerable<T>IDisposable的自定义对象(而不是迭代器块),那么在foreach中使用它时将不会被丢弃。只有通过IEnumerator<T>创建的GetEnumerator才会出现。

答案 1 :(得分:3)

如果你想处理IEnumerable<T>,你需要自己使用using语句(或手动尝试/最后)。 foreach循环自动处理IEnumerable<T> - 只返回它返回的迭代器。

所以,你需要:

using (var enumerable = new MyEnumerable())
{
    foreach (var element in enumerable)
    {
        ...
    }
}

MyEnumerable是否使用迭代器块或其他代码实现IEnumerable<T>没有任何区别。