Dün, özellikle üretilen kodun neye benzediğini ve the GetAwaiter()
/ BeginAwait()
/ EndAwait()
çağrılarını inceleyerek yeni C # "async" özelliği hakkında bir konuşma yapıyordum .
C # derleyicisi tarafından oluşturulan durum makinesine biraz ayrıntılı baktık ve anlayamadığımız iki nokta vardı:
- Oluşturulan sınıfın neden hiç kullanılmadığı (ve sınıfın uygulanmadığı ) bir
Dispose()
yöntem ve$__disposing
değişken içerdiğiIDisposable
. state
Herhangi bir çağrıdan önce dahili değişken neden 0 olarak ayarlanırEndAwait()
, 0 normalde "bu ilk giriş noktasıdır" anlamına gelir.
İlk noktanın async yöntemi içinde daha ilginç bir şey yaparak cevaplanabileceğinden şüpheleniyorum, ancak herhangi bir başka bilgi varsa bunu duymaktan memnuniyet duyarım. Ancak bu soru daha çok ikinci konu ile ilgilidir.
İşte çok basit bir örnek kod parçası:
using System.Threading.Tasks;
class Test
{
static async Task<int> Sum(Task<int> t1, Task<int> t2)
{
return await t1 + await t2;
}
}
... ve MoveNext()
durum makinesini uygulayan yöntem için üretilen kod . Bu doğrudan Reflektör'den kopyalanır - Açıklanamayan değişken adlarını düzeltmedim:
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);
}
}
Uzun ama bu sorunun önemli satırları:
// 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();
Her iki durumda da, daha sonra açıkça gözlemlenmeden önce devlet tekrar değiştirilir ... öyleyse neden onu 0 olarak ayarladınız? Eğer MoveNext()
bu noktada tekrar çağrıldı (doğrudan veya üzeri Dispose
) etkin ve eğer ... anlarım kadarıyla tamamen uygunsuz olacağını, yine zaman uyumsuz yöntemini başlayacaktı MoveNext()
değildir denilen durum değişikliğinin alakasız.
Bu sadece daha açık bir açıklamaya sahip olabileceği asenkron için tekrarlayıcı blok oluşturma kodunu yeniden kullanan derleyicinin bir yan etkisi midir?
Önemli sorumluluk reddi
Açıkçası bu sadece bir CTP derleyicisidir. Son sürümden önce ve muhtemelen bir sonraki CTP sürümünden önce bir şeylerin tamamen değişmesini bekliyorum. Bu soru hiçbir şekilde bu C # derleyicisindeki bir kusur veya böyle bir şey olduğunu iddia etmeye çalışmamaktadır. Ben sadece bunun kaçırdığım ince bir nedeni olup olmadığını anlamaya çalışıyorum :)