SORU
17 ŞUBAT 2011, PERŞEMBE


# 5 CTP uyumsuz C: neden iç "devlet" EndAwait çağırmadan önce oluşturulan kodu ayarlamak için 0?

Dün verdiğin bir şey için yeni bir C# "uyumsuz" özelliği, özellikle kazıcı içine ne oluşturulan kod görünüyordu, ve the GetAwaiter() / BeginAwait() / EndAwait() çağırır.

Devlet makine C tarafından oluşturulan bazı ayrıntılı olarak inceledik# derleyicisi, anlayamadık iki yönü vardı:

  • İçeren hiç kullanmadım görünen Dispose() yöntem $__disposing bir değişken, neden oluşturulan sınıf (sınıf IDisposable sağlamayan).
  • state dahili değişken herhangi bir 0 normal demek için göründüğünde EndAwait() aramadan önce 0 olarak ayarlanır neden "bu ilk giriş noktasıdır".

Eğer kimse herhangi bir ek bilgi varsa duymak isterim, ancak ilk nokta zaman uyumsuz yöntem içinde daha ilginç bir şey yaparak cevap olabilir sanırım. Bu soru ikinci nokta hakkında daha fazla ancak.

İşte örnek kod çok basit bir parça

using System.Threading.Tasks;

class Test
{
    static async Task<int> Sum(Task<int> t1, Task<int> t2)
    {
        return await t1   await t2;
    }
}

... ve burada devlet makine uygulayan MoveNext() yöntemi için oluşturulan alır kodu. Bu doğrudan Reflektör - tarifsiz değişken adları sabit birşey yok: kopyalanmış

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 zaman oldu, ama bu soru için önemli çizgiler vardır:

// 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, devletin daha sonra bir sonraki açıkça görülmektedir... neden 0 hiç set? önce tekrar değişti. Eğer MoveNext() denilen yine bu noktada (ya doğrudan ya da üzerinden Dispose Bu etkili başlangıç zaman uyumsuz yöntem yeniden bir karar tamamen uygunsuz olarak görebildiğim kadarıyla... eğer MoveNext()değilaradı, durumu değişikliği ile ilgisi yoktur.

Bu sadece daha bariz bir açıklama olabilir yan etkisi derleyici yeniden yineleyici bloğu nesil kod için zaman uyumsuz bir mi?

Önemli yasal uyarı

Tabi bu sadece CTP bir derleyici. Ben tam şey bir sonraki CTP yayın bile önce son sürümü önce - ve büyük olasılıkla değiştireceğini bekliyor. Bu soru hiçbir şekilde bu C bir kusur olduğunu iddia etmeye çalışıyor# derleyici ya da böyle bir şey. Sadece özledim bu:) ince bir nedeni var mı çalışmak için çalışıyorum

CEVAP
23 NİSAN 2011, CUMARTESİ


Tamam, sonunda gerçek bir cevap yok. Ben de biraz takım VB bölümünden Lucian Wischik gerçekten bunun için iyi bir nedeni olduğunu doğruladı sadece sonra benim dışımda, ama işe yaradı. Kendisine çok teşekkür ediyor ve sizi memnun kayalar his blog ziyaret edin.

0 değeri, burada olduğu için çok özeldeğilsadece normal bir durumda await önce olabilir geçerli bir durum. Özellikle, devlet makinesini başka bir yerde test sonu olabilecek bir durum değil. Non-pozitif herhangi bir değeri kullanarak, o zaman, inanıyorum ki bu: -1 . bunun için kullanılmıyor ^em>mantıklı-1 normalde aracı olarak yanlış, "" bitirdim. Ekstra bir anlamı şu an 0 durumuna veriyoruz iddia edebilirim, ama sonuçta çok da önemli değil. Bu sorunun amacı devleti ayarlı neden bulmak.

Değeri ise yakalanan bir istisna biter bekliyor uygundur. Tekrar aynı bildirimi tekrar bekliyor, ama biz buraya edebilirizyapmayınbu durumda "sadece kod tür atlanır olur." aksi bekliyor bu noktadan sonra geri dönmek üzereyim anlamı Basit bir örnekle göstermek için. Şimdi ikinci CTP kullanıyorum, üretilen kod söz konusu olduğu için biraz farklı olduğunu unutmayın.

İşte zaman uyumsuz yöntem:

static async Task<int> FooAsync()
{
    var t = new SimpleAwaitable();

    for (int i = 0; i < 3; i  )
    {
        try
        {
            Console.WriteLine("In Try");
            return await t;
        }                
        catch (Exception)
        {
            Console.WriteLine("Trying again...");
        }
    }
    return 0;
}

Kavramsal olarak, SimpleAwaitable herhangi bir awaitable - belki bir görev, belki başka bir şey olabilir. Benim test amaçlı, her zaman IsCompleted yanlış verir ve GetResult bir istisna atar.

İşte MoveNext için oluşturulan kodu:

public void MoveNext()
{
    int returnValue;
    try
    {
        int num3 = state;
        if (num3 == 1)
        {
            goto Label_ContinuationPoint;
        }
        if (state == -1)
        {
            return;
        }
        t = new SimpleAwaitable();
        i = 0;
      Label_ContinuationPoint:
        while (i < 3)
        {
            // Label_ContinuationPoint: should be here
            try
            {
                num3 = state;
                if (num3 != 1)
                {
                    Console.WriteLine("In Try");
                    awaiter = t.GetAwaiter();
                    if (!awaiter.IsCompleted)
                    {
                        state = 1;
                        awaiter.OnCompleted(MoveNextDelegate);
                        return;
                    }
                }
                else
                {
                    state = 0;
                }
                int result = awaiter.GetResult();
                awaiter = null;
                returnValue = result;
                goto Label_ReturnStatement;
            }
            catch (Exception)
            {
                Console.WriteLine("Trying again...");
            }
            i  ;
        }
        returnValue = 0;
    }
    catch (Exception exception)
    {
        state = -1;
        Builder.SetException(exception);
        return;
    }
  Label_ReturnStatement:
    state = -1;
    Builder.SetResult(returnValue);
}

Label_ContinuationPoint taşımak için bu kod geçerli yapmak zorundaydım yoksa goto deyimi kapsamı içinde değil - ama bu cevabı etkilemez.

GetResult istisna atar ne olacağını düşün. Catch bloğu ile i, ve sonra döngü tekrar (i hala 3'ten daha az olduğunu varsayarsak) artış gideceğiz. Hala GetResult aramadan önce ne olursa olsun... ama içeri girince try engellemegerekir""ve GetAwaiter bir daha arama... ve bunu 1 değil eğer devlet. sadece yapacağız Deneyin Yazdır state = 0 atama olmadan, mevcut awaiter kullanın ve Console.WriteLine çağrı atlar.

Kod oldukça dolambaçlı bir bit ile çalışmak, ama sadece takım hakkında düşünmek zorunda şey türden bir gösteri. Bu uygulama :) ben sorumlu değilim sevindim

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Elly Awesome

    Elly Awesome

    15 ŞUBAT 2010
  • Jesse Pimenta

    Jesse Piment

    5 EKİM 2011
  • Project Mooncircle

    Project Moon

    6 Aralık 2009