在尝试使用迭代器块之后,我注意到生成的IL代码并不是我所期望的。而不是try-finally块,生成了一个try-fault块,这是我从未见过的。我注意到编译器不允许我在'手写'C#中使用fault关键字。
2之间有什么区别吗?
C#代码:
static IEnumerable<string> ReadAllLines(string fileName)
{
using (var file = System.IO.File.OpenText(fileName))
{
string s;
while ((s = file.ReadLine()) != null)
{
yield return s;
}
}
}
MSIL代码:
.method private hidebysig newslot virtual final instance bool MoveNext() cil managed
{
.override [mscorlib]System.Collections.IEnumerator::MoveNext
.maxstack 3
.locals init (
[0] bool CS$1$0000,
[1] int32 CS$4$0001,
[2] string CS$0$0002,
[3] bool CS$4$0003)
L_0000: ldarg.0
// try body
L_008d: leave.s L_0097
L_008f: ldarg.0
L_0090: call instance void ConsoleApplication2.Program/<ReadAllLines>d__0::System.IDisposable.Dispose()
L_0095: nop
L_0096: endfinally
L_0097: nop
L_0098: ldloc.0
L_0099: ret
.try L_0000 to L_008f fault handler L_008f to L_0097
}
有趣的行是指定了错误处理程序的IL的最后一行,在正常的try-finally块中指定了finally处理程序。
答案 0 :(得分:8)
是的,最后一个块总是在帧退出时执行。仅当异常在帧之后展开时才执行故障块。 MoveNext中的错误块保留了从ReadAllLines迭代器的try块抛出的异常情况的使用语义。必须使用其他一些机制来保留迭代器正常退出时的使用语义。