이 컴파일러 생성 열거 자료는 무엇을 의미합니까?
-
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
. 그래도 Case 3에 빈 스위치가 왜 있는지 또는 왜 m__Finallya
a finally
차단하다. (정상적으로 그리고 내부에서 실행하는 것 사이에 의미 적 차이가 있습니까? finally
차단하다? 내 코드에없는 Cer 's 외에.)
참고로 다음은 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을 따라 잡기 위해 고군분투하는 단순히 반사기입니다 (반복자 블록은 유효한 IL 인 "정상"C#과 관련이 없기 때문에). 특히, ret
후에 finally
차단하다.
다른 팁
원래 반복자 블록의 모습을 보여주지 않았지만 반사기 및 컴파일러 생성 코드에 대한 내 경험은 컴파일러가 동등한 IL을 사용하기 때문에 항상 정확하게 완전히 분리되지는 않는다는 것입니다. 씨#.
나는있다 반복자 블록 구현에 관한 기사 조금 도움이 될 수 있지만 컴파일 된 코드가 어떻게 보이는지 너무 걱정하지 않을 것입니다. 경우에 따라 C# 컴파일러는 컴파일러를 더 간단하게 유지하는 근거로 거의 불필요한 코드를 생성하고 있습니다. 반복자 블록은 올바르게 잡기가 매우 까다로워 야합니다 (결국 블록 및 반복자 처리로 매우 복잡해질 수 있습니다).
나는 C# 컴파일러가 바보라고 주장 할 수있다. 런 타임에 의해 Jitte가있을 때이 코드가 매우 다르게 보일 수도 있습니다 (불쾌한 쓰레기는 생략됩니다).
어쨌든, 당신은 주 머신에 익숙할까요? C# (수율 재료)에 발전기를 쓰면 컴파일러 에게이 생성기를 상태 머신으로 구현하는 익명 유형을 방출하도록 지시합니다. 이것은 검증 가능한 멋진 공식적인 접근법입니다. 그것이 아마도 그것이하는 것처럼 보이는 이유 일 것입니다.