어제는 생성 된 코드가 어떻게 생겼는지에 특히 탐구에서, 기능 "비동기"새로운 C 번호에 대한 이야기를 제공하고, 한 the GetAwaiter()
/ BeginAwait()
/ EndAwait()
전화.
우리는 C # 컴파일러에 의해 생성 된 상태 머신에 대해 자세히 살펴 보았고 이해할 수없는 두 가지 측면이있었습니다.
- 생성 된 클래스에
Dispose()
메소드와$__disposing
변수 가 포함되어 있는데 왜 사용되지 않는 것 같습니다 (그리고 클래스는 구현하지 않습니다IDisposable
). - 0이 일반적으로 "이것은 초기 진입 점"을 의미하는 것처럼 보일 때 내부
state
변수가를 호출하기 전에 0으로 설정된 이유EndAwait()
입니다.
나는 누군가가 더 많은 정보를 가지고 있다면 그것을 기뻐할지라도 비동기 방법 내에서 더 흥미로운 것을 수행함으로써 첫 번째 요점에 대답 할 수 있다고 생각합니다. 그러나이 질문은 두 번째 요점에 관한 것입니다.
다음은 매우 간단한 샘플 코드입니다.
using System.Threading.Tasks;
class Test
{
static async Task<int> Sum(Task<int> t1, Task<int> t2)
{
return await t1 + await t2;
}
}
... MoveNext()
상태 머신을 구현하는 메소드에 대해 생성되는 코드는 다음과 같습니다 . 이것은 Reflector에서 직접 복사됩니다-말할 수없는 변수 이름을 수정하지 않았습니다 :
public void MoveNext()
{
try
{
this.$__doFinallyBodies = true;
switch (this.<>1__state)
{
case 1:
break;
case 2:
goto Label_00DA;
case -1:
return;
default:
this.<a1>t__$await2 = this.t1.GetAwaiter<int>();
this.<>1__state = 1;
this.$__doFinallyBodies = false;
if (this.<a1>t__$await2.BeginAwait(this.MoveNextDelegate))
{
return;
}
this.$__doFinallyBodies = true;
break;
}
this.<>1__state = 0;
this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();
this.<a2>t__$await4 = this.t2.GetAwaiter<int>();
this.<>1__state = 2;
this.$__doFinallyBodies = false;
if (this.<a2>t__$await4.BeginAwait(this.MoveNextDelegate))
{
return;
}
this.$__doFinallyBodies = true;
Label_00DA:
this.<>1__state = 0;
this.<2>t__$await3 = this.<a2>t__$await4.EndAwait();
this.<>1__state = -1;
this.$builder.SetResult(this.<1>t__$await1 + this.<2>t__$await3);
}
catch (Exception exception)
{
this.<>1__state = -1;
this.$builder.SetException(exception);
}
}
길지만이 질문의 중요한 내용은 다음과 같습니다.
// End of awaiting t1
this.<>1__state = 0;
this.<1>t__$await1 = this.<a1>t__$await2.EndAwait();
// End of awaiting t2
this.<>1__state = 0;
this.<2>t__$await3 = this.<a2>t__$await4.EndAwait();
두 경우 모두 다음에 분명히 관찰되기 전에 상태가 다시 변경됩니다. 왜 0으로 설정해야합니까? 경우 MoveNext()
이 시점에서 다시 호출했다 (직접 또는 경유 Dispose
) 효과적으로 그리고 만약 ... 내가 말할 수있는 늘어나는만큼 전적으로 부적합 할 수있는, 다시 비동기 방식을 시작할 것이라고 MoveNext()
되지 않는다 라고, 상태의 변화는 무관하다.
이것은 컴파일러가 반복기 블록 생성 코드를 비동기식으로 재사용하여 더 명확한 설명을 할 수있는 부작용입니까?
중요한 면책
분명히 이것은 단지 CTP 컴파일러 일뿐입니다. 최종 릴리스 이전과 다음 CTP 릴리스 이전에도 상황이 완전히 바뀔 것으로 기대합니다. 이 질문은 이것이 C # 컴파일러 또는 그와 같은 결함이라고 주장하려고 시도하지 않습니다. 나는 내가 놓친 미묘한 이유가 있는지 알아 내려고 노력하고있다. :)