这两个问题几乎可以回答我自己的问题,但并不完全。考虑这是对这些问题的后续问题。
我理解,当枚举器完成后,foreach
循环将Dispose
。
我的问题是:
如果有问题的枚举器实际上是GetEnumerator()/yield
类的ac#iterator块(即IEnumerable<T>
),它本身实现了IDisposable
,我可以确定对象本身是否会被处置?或者我是否需要在GetEnumerator()/MoveNext()/Current
块内明确调用using
?
编辑: This snippet演示@ JonSkeet的答案。
编辑#2: This snippet,基于@ JonSkeet的评论,展示了理想的用法。迭代器块负责所需资源的生命周期,而不是可枚举对象本身。这样,如果需要,可以多次枚举枚举 - 每个枚举都有自己的资源可供使用。
答案 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>
没有任何区别。