2009-08-01 56 views
11

經過試驗迭代器塊後,我注意到生成的IL代碼並不是我所期望的。生成一個嘗試錯誤塊,而不是try-finally塊,這是我從未見過的。我注意到編譯器不允許我在'handwritten'C#中使用fault關鍵字。迭代器塊在IL中產生嘗試錯誤

2是否有區別?

C#代碼:

static IEnumerable<string> ReadAllLines(string fileName) 
{ 
    using (var file = System.IO.File.OpenText(fileName)) 
    { 
     string s; 
     while ((s = file.ReadLine()) != null) 
     { 
      yield return s; 
     } 
    } 
} 

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 
} 

有趣的線是IL的最後一行,其中指定了故障處理程序,其中,在正常的try-finally塊一個最後指定處理程序。

+1

爲什麼使用.net-4.0特別標記?版本之間有這種變化嗎? – 2009-08-02 07:44:49

回答

8

是的,Finally塊總是在幀退出時執行。只有當一個異常退出框架時才執行故障塊。 MoveNext中的故障塊保留了從ReadAllLines迭代器的try塊拋出的異常情況的使用語義。在正常退出迭代器時,必須使用其他一些機制來保留使用的語義。

+0

所以只有在處理try部分中的異常時調用Dispose中的Dispose。 而常規的dispose由生成的IEnumerator的Dispose方法處理。 – 2009-08-01 22:38:10