Repetidor bloco gera tentativa-erro no IL
Pergunta
Depois de experimentar com um bloco iterador notei o código IL gerado não é o que eu esperava que fosse. Em vez de um try-finally bloquear um bloco try-falha é gerada, que eu nunca vi. Notei que o compilador não permite que eu use a falha de palavras-chave em 'manuscrito' C #.
Existe alguma diferença entre o 2?
C # código:
static IEnumerable<string> ReadAllLines(string fileName)
{
using (var file = System.IO.File.OpenText(fileName))
{
string s;
while ((s = file.ReadLine()) != null)
{
yield return s;
}
}
}
Código 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
}
A linha interessante é a última linha do IL onde um manipulador de falhas for especificado, onde em um normal de try-finally bloquear uma finalmente é especificado manipulador.
Solução
Sim, um bloco finally sempre executa no quadro saída. Um bloco de culpa executa somente se uma exceção é desenrolado após o quadro. O bloco de falha no MoveNext preserva as usando semântica para o caso de uma exceção lançada a partir do bloco try do iterador ReadAllLines. Algum outro mecanismo deve estar em uso para preservar os que usam a semântica de saída normal do iterador.