我发现了一个没有调用finally块的情况。
重点:
using System;
using System.Collections.Generic;
using System.Threading;
using System.ComponentModel;
class MainClass{
static IEnumerable<int> SomeYieldingMethod(){
try{
yield return 1;
yield return 2;
yield return 3;
}finally{
Console.WriteLine("Finally block!");
}
}
static void Main(){
Example(7);
Example(2);
Example(3);
Example(4);
}
static void Example(int iterations){
Console.WriteLine("\n Example with {0} iterations.", iterations);
var e = SomeYieldingMethod().GetEnumerator();
for (int i = 0; i< iterations; ++i) {
Console.WriteLine(e.Current);
e.MoveNext();
}
}
}
结果:
Example with 7 iterations.
0
1
2
3
Finally block!
3
3
3
Example with 2 iterations.
0
1
Example with 3 iterations.
0
1
2
Example with 4 iterations.
0
1
2
3
Finally block!
所以,看起来如果某人正在使用我的让步方法并使用枚举器(而不是foreach)手动处理它,那么我的finally块永远不会被调用。
有没有办法确保我的方法最终确定它的资源? 这是“产量语法糖”中的一个错误,还是它应该按预期工作?
答案 0 :(得分:3)
那是因为他们没有正确使用迭代器。该代码应为:
using(var e = SomeYieldingMethod().GetEnumerator())
{
for (int i = 0; i< iterations; ++i) {
Console.WriteLine(e.Current);
e.MoveNext();
}
}
using
在这里很重要。这是映射到finally
等的(假设迭代器还没有自然完成)。
具体来说,如果迭代器实现foreach
,Dispose()
显式在迭代器上调用IDisposable
。自IEnumerator<T> : IDisposable
起,这包括几乎所有迭代器(警告:foreach
不需要IEnumerator[<T>]
)。
答案 1 :(得分:1)
它按预期工作,最终在错误时执行或者当你到达块时,如果它们从不枚举直到结束,你永远不会到达那个块的末尾,所以最终不应该执行。
Yield创建一个类来表示你的方法作为一个方法+状态放入成员+放置的地方,所以你每次都“恢复”这个方法,如果你的最终放在最后,你永远不会到达终点的意见和你永远不会列举到最后。如果你希望每次都执行finally块,你需要做一些急切的评估,但是你不能说“我想让它流式传输,最后在最后被调用,但让编译器自动检测到客户端代码,如果它永远不会流到最后,然后最后调用“。没有“适当”的时间来最终打电话,因为你知道他可能会将调查员传递给另一个项目&amp;让它继续列举,如果它继续列举&amp;编译器错误地调用了最终?