2009-08-01 4 views
11

반복기 블록을 실험 한 후에 생성 된 IL 코드가 예상 한 것과 다릅니다. try-finally 블록 대신 try-fault 블록이 생성됩니다. 나는 컴파일러가 'handwritten'C#에서 fault 키워드를 사용할 수 없다는 것을 알아 차렸다.Iterator 블록이 IL에서 try-fault를 생성합니다.

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의 마지막 줄입니다 finally 핸들러가 지정됩니다.

+1

특별히이 태그가 .net-4.0에 태그되어 있습니까? 버전간에 변경 되었습니까? –

답변

8

예, Finally 블록은 항상 프레임 이탈시 실행됩니다. 오류 블록은 예외가 프레임을 지나서 풀려 질 때만 실행됩니다. MoveNext의 오류 블록은 ReadAllLines 반복기의 try 블록에서 throw 된 예외의 경우에 사용 의미를 유지합니다. 반복기에서 정상적으로 종료 할 때 사용 의미를 보존하려면 다른 메커니즘이 사용 중이어야합니다.

+0

그래서 Try 부분의 예외를 처리 할 때만 Dispose를 호출합니다. 일반 dispose는 생성 된 IEnumerator의 Dispose 메서드에 의해 처리됩니다. –