2011-07-30 18 views
5

Bazı asenkron/bekletme kodlarını zincirleme görevlere dönüştürüyorum, böylece yayımlanan çerçevede kullanabilirim. bekliyoruz koduTaskCompletionSource olmadan görev zinciri oluşturma?

Task<TraumMessage> Invoke(string verb) {} 
Task<TraumMessage> Memorize() {} 

Ben zincire Invoke umuyordum ve MemorizeMemorize tarafından üretilen görevi dönmek için bu

public async Task<TraumMessage> Get() { 
    var message = await Invoke("GET"); 
    var memorized = await message.Memorize(); 
    return memorized; 
} 

benziyor, ama bu bir Task<Task<TraumMessage> sonuçlanır. i sona erdi ettik çözüm benim sinyali olarak bir TaskCompletionSource<TraumMessage> geçerli: TaskCompletionSource olmadan bunu yapmanın bir yolu

public Task<TraumMessage> Get() { 
    var completion = new TaskCompletionSource<TraumMessage>(); 
    Invoke("GET").ContinueWith(t1 => { 
    if(t1.IsFaulted) { 
     completion.SetException(t1.Exception); 
     return; 
    } 
    t1.Result.Memorize().ContinueWith(t2 => { 
     if(t2.IsFaulted) { 
     completion.SetException(t2.Exception); 
     return; 
     } 
     completion.SetResult(t2.Result); 
    }); 
    }); 
    return completion.Task; 
} 

var mı?

cevap

1

Sanırım bu, istediğiniz şeyi başarmanın tek yoludur. Farklı Görevleri Zincirleme, devamlılık API'ları tarafından desteklenmez, bu nedenle çalışmayı koordine etmeniz gerektiği gibi bir TaskCompletionSource kullanmaya başvurmalısınız.

Bu makinede Async CTP yüklü yok, ancak neden yaptıklarını görmek için bir decompiler (veya IL'nin nasıl okunacağını biliyorsanız ILDASM) ile birlikte bir kod kullanmıyorsunuz. Bahse girerim, TCS kodunuza çok benzer bir şey yapar.

+0

Jon Skeet'in EduAsync serisi sayesinde, async/await'ın kapağının altına baktım ve temelde bir devlet makinesini çalıştıran bir sınıf oluşturuyor. Bu yaklaşımı daha önce de kullandım, ama TCS yaklaşımından bile daha sıkıcı. –

+0

Ah, bunu daha çok düşündüm ve 2. görevin devam etmesinin sonucunu bekleyen 1. görevin devam etmesini engellemek istemediğiniz sürece saf sürekliliğin bir yolu yoktur. Eğer yıldızların çalınması hizalı olsaydı, bunun anlamı çok azdır, ama teorik olarak 2. görevin nasıl yaratıldığına dair bir fikriniz olmadığından (örneğin, tamamen farklı bir görev zamanlayıcısı veya APM olabilir) bunun için hiçbir garanti yoktur. Yani sonuçta bekleyen bir iş parçacığı engellediğini varsayalım. Neyi kastettiğimi görmek istiyorsan, cevapımı güncelleyeceğim. –

+1

http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx adresinden Stephen Taub, 'TaskCompletionSource'u bu deseni uygulamak için' Sonra 'adlı yardımcı bir yöntemle tamamlar. – Govert

0

Eklenmiş alt görevleri kullanabilirsiniz. Tüm görevler tamamlandığında ana görev yalnızca tamamlanmış duruma geçecektir. İstisnalar ana görev için çoğaltılır. 'dan sonra atandıktan sonra, üst görevlerin delege bitmiş olduğu, ancak üst görevlerin devamları çalıştırıldığında ayarlanacak olan sonuç taşıyıcısına ihtiyacınız olacaktır. Bunun gibi

:

public class Holder<T> where T: class 
{ 
    public T Value { get; set; } 
} 

public Task<Holder<TraumMessage>> Get() { 
    var invokeTask = Invoke("GET"); 
    var result = invokeTask.ContinueWith<Holder<TraumMessage>>(t1 => { 
    var holder = new Holder<TraumMessage>(); 
    var memorizeTask = t1.Result.Memorize(); 
    memorizeTask.ContinueWith(t2 => { 
     holder.Value = t2.Result; 
    }, TaskContinuationOptions.AttachedToParent); 
    return holder; 
    }); 
    return result; 
} 
4

Evet, çerçeve tam olarak istediğiniz ne için kullanışlı bir Unwrap() uzantısı yöntemi ile geliyor.

Invoke("GET").ContinueWith(t => t.Result.Memorize()).Unwrap(); 

İptal işlemi yapıyorsanız, iptal edicilerini uygun yerlere aktarmanız gerekir.

İlgili konular