4

かなり複雑なyield-returnsメソッドを作成しIEnumerable<string>ましたが、Reflectorでコンパイラーの出力を調べたところ、コンパイラーによって生成された実装の特定の部分がわかりませんでした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
4

3 に答える 3

5

元の反復子ブロックがどのように見えるかを示していませんが、Reflector とコンパイラで生成されたコードの私の経験では、コンパイラは同等のものを持たない IL を使用するため、常に完全に正確に逆コンパイルできるとは限りません。 C#.

イテレータ ブロックの実装に関する記事がありますが、これは少し役立つかもしれませんが、コンパイルされたコードがどのように見えるかについてはあまり心配しません。場合によっては、C# コンパイラが不要なコードを生成することはほぼ確実です。これは、コンパイラを単純に保つためです。イテレータ ブロックを正しく処理するには非常に注意が必要です (finally ブロックとイテレータの処理により、非常に複雑になる可能性があります)。そのため、JIT を信頼して、生成されたコードのスイッチ/ケースなどの不要なビットを最適化するのが合理的だと思います。

于 2009-02-17T07:48:31.217 に答える
4

これは、生成されたILに追いつくのに苦労しているリフレクターです(イテレーターブロックは、有効なILである限り、「通常の」C#に関連付ける必要がないため)。特に、はブロックのret後にあります。finally

于 2009-02-17T07:46:17.790 に答える
1

私はC#コンパイラがばかげていると主張することができます(おそらく少しばかげています)。また、実行時にこのコードが非常に異なって見える可能性もあります(厄介なゴミはすべて省略されます)。

とにかく、あなたはおそらくステートマシンに精通していますか?ジェネレーターをC#(yield stuff)で作成する場合、このジェネレーターをステートマシンとして実装する匿名型を発行するようにコンパイラーに指示します。これは、検証可能であることを目的とした優れた正式なアプローチです。それがおそらくそれがそのように見える理由です。

于 2009-02-17T07:35:48.517 に答える