このコンパイラで生成さ列挙子は何を意味するのでしょうか?
-
23-08-2019 - |
質問
私は歩留まり-リターンがIEnumerable<string>
が、私は反射でコンパイラの出力を検査するとき、私は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();
}
私は推測する(または期待して)反射器が外switch
の閉じ括弧を紛失していること、そしてそれがreturn
後に直接でなければならないことです。そこケース3内の空のスイッチがある、またはなぜm__Finallya
がfinally
ブロックに呼ばれている理由それでも、私は理解していません。 (通常とfinally
ブロック内で実行している間の意味の違いはありますか?CERの以外に、私は私のコードでは持たない。)
は、参考のため、ここでは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
解決
これは単に反射板は、(反復子ブロックは限りがIL有効であるように、「通常」のC#を関連付ける必要がないので)、生成されたILに追いつくために苦労しています。特に、ret
はfinally
ブロックの後である。
他のヒント
あなたはコンパイラが持っていないいくつかのILを使用しているため、元の反復子ブロックのように見えるが、私のリフレクターの経験と、コンパイラによって生成されたコードは、それが常に完全に正確にコンパイルするために管理していないということが何であるかを示していませんC#での同等の
私はあなたの少しを助けるかもしれ反復子ブロックの実装について 記事を持っていますが、私は、コンパイルされたコードがどのように見えるかについてはあまり心配しないでしょう。いくつかのケースではC#コンパイラは、ほぼ確実にそれは単純なコンパイラを保持していることを理由に不必要なコードを生成しています。イテレータブロックは、権利を取得することは非常にトリッキーされている必要があります(それはfinallyブロックとイテレータの処分で、非常に複雑に得ることができる)ので、私はそれだけであなたの生成されたコードのスイッチ/ケースのような不要なビットを離れて最適化するために、JITを信頼するのが妥当だと思います。
私はC#コンパイラは、(それはおそらく少しばかげているのです)、愚かであることを主張することができます。それは(すべてが嫌なゴミが省略されます)実行時でJITコンパイルされたときに、このコードは非常に異なって見えることも十分に可能です。
とにかく、ステートマシンと多分ご存知?もしC#(利回りのもの)で発電機を書くときには、ステートマシンとしてこのジェネレータを実装して匿名型を発するようにコンパイラに指示します。これは、検証可能であることを意味している素敵なフォーマルなアプローチです。それはおそらく、それはそれがない道に見える理由です。