2009-02-17 94 views
4

我寫了一個相當複雜的方法,它產量的回報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(); 
} 

我m猜測(或希望)Reflector錯位了外部switch的右大括號,並且它應該緊接在return之後。不過,我不明白爲什麼在情況3中存在空開關,或者爲什麼m__Finallyafinally塊中被調用。 (有沒有正常運行之間和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

這只是反射器努力跟上已經生成的IL(因爲只要它們是有效的IL,迭代器塊不必與「正常」C#相關)。特別是,ret位於finally塊之後。

1

我可能會爭辯說C#編譯器很愚蠢,(它可能有點愚蠢)。當運行時間爆發時(這些討厭的垃圾被省略),這段代碼看起來也非常不同。

無論如何,你可能熟悉狀態機?當你用C#編寫生成器(yield stuff)時,你告訴編譯器發出一個匿名類型來實現這個生成器作爲狀態機。這是一個很好的正式方法,可以驗證。這可能是它看起來如此的原因。

+0

你可以確信編譯器/是/愚蠢的,因爲所有的程序都相當愚蠢。 (這是Godel不完備定理的必然結果) – BCS 2009-02-17 17:59:51

5

你還沒有展示你原來的迭代器塊的樣子,但是我對Reflector和編譯器生成的代碼的經驗是它並不總是能夠完全準確地反編譯,因爲編譯器使用了一些不在C#中有一個等價物。

我有一個article about iterator block implementation它可以幫助你一點,但我不會太擔心編譯代碼的樣子。在某些情況下,C#編譯器幾乎肯定會生成不必要的代碼,理由是這樣可以使編譯器更簡單。迭代器塊必須非常棘手才能正確使用(它可能變得非常複雜,最終會阻塞和迭代器處置),所以我認爲只需相信JIT就可以優化生成的代碼中的開關/大小寫等不必要的位是合理的。