I wrote a fairly complex method that yield-returns IEnumerable<string>
, but when I inspected the compiler output in Reflector, I didn't understand a specific part of the compiler-generated implementation of IEnumerator
:
void IDisposable.Dispose()
{
switch (this.<>1__state)
{
case 1:
case 2:
case 3:
switch (this.<>1__state) // empty switch! why?!
{
}
break;
default:
return;
try // What?! AFTER return?!
{
}
finally // is the try-finally block anyhow relevant?
{
this.<>m__Finallya();
}
break;
}
this.<>m__Finally7();
}
I'm guessing (or hoping) that Reflector misplaced the closing brace of the outer switch
, and that it should be directly after the return
. Still, I don't understand why there is an empty switch in case 3, or why m__Finallya
is being called in a finally
block. (Is there a semantic difference between running normally and inside a finally
block? Other than CER's, which I don't have in my code.)
For reference, here is the IL:
.method private hidebysig newslot virtual final
instance void System.IDisposable.Dispose() cil managed
{
.override [mscorlib]System.IDisposable::Dispose
// Code size 69 (0x45)
.maxstack 2
.locals init ([0] int32 CS$0$0000,
[1] int32 CS$0$0001)
IL_0000: ldarg.0
IL_0001: ldfld int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: sub
IL_000a: switch (
IL_001c,
IL_001c,
IL_001c)
IL_001b: ret
IL_001c: ldarg.0
IL_001d: ldfld int32 FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>1__state'
IL_0022: stloc.1
IL_0023: ldloc.1
IL_0024: ldc.i4.2
IL_0025: sub
IL_0026: switch (
IL_0035,
IL_0035)
IL_0033: br.s IL_003e
.try
{
IL_0035: leave.s IL_003e
} // end .try
finally
{
IL_0037: ldarg.0
IL_0038: call instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finallya'()
IL_003d: endfinally
} // end handler
IL_003e: ldarg.0
IL_003f: call instance void FBD.TIP.Reader.MissingMessagesReader/'<GetMissingMessages>d__0'::'<>m__Finally7'()
IL_0044: ret
} // end of method '<GetMissingMessages>d__0'::System.IDisposable.Dispose
You haven't shown what your original iterator block looks like, but my experience of Reflector and compiler-generated code is that it doesn't always manage to decompile entirely accurately, because the compiler uses some IL which doesn't have an equivalent in C#.
I've got an article about iterator block implementation which may help you a bit, but I wouldn't worry too much about what the compiled code looks like. In some cases the C# compiler is almost certainly generating unnecessary code on the grounds that that keeps the compiler simpler. Iterator blocks must have been very tricky to get right (it can get very complicated, with finally blocks and iterator disposal) so I think it's reasonable to just trust the JIT to optimise away the unnecessary bits like the switch/case in your generated code.
That is simply reflector struggling to keep up with the IL that has been generated (since iterator blocks don't have to relate to "normal" C# as long as they are valid IL). In particular, the ret
is after the finally
block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With