Yeni async/await modelini kullanarak bir olay tetiklendiğinde tamamlanan bir Task
oluşturmak oldukça kolaydır;Genel amaç FromEvent yöntemi
public class MyClass
{
public event Action OnCompletion;
}
public static Task FromEvent(MyClass obj)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
obj.OnCompletion +=() =>
{
tcs.SetResult(null);
};
return tcs.Task;
}
Bu da verir:
await FromEvent(new MyClass());
sorunu da await
istiyorum her sınıfta her olay için yeni bir FromEvent
yöntem oluşturmak için gerektiğidir sadece bu modeli takip etmek gerekir üzerinde. Bu gerçekten çok hızlı bir şekilde gerçekten çok hızlı olabilir ve çoğunlukla sadece bir kod yazısıdır.
İdeal böyle bir şey yapabilmek istiyorum:
await FromEvent(new MyClass().OnCompletion);
Sonra herhangi bir örneği herhangi bir olay için aynı FromEvent
yöntemi yeniden kullanabilirsiniz. Böyle bir yöntem oluşturmaya çalışırken biraz zaman harcadım ve bir kaç engel var. üstündeki kod aşağıdaki hata üretir için: Bildiğim kadarıyla söyleyebilirim
The event 'Namespace.MyClass.OnCompletion' can only appear on the left hand side of += or -=
, şimdiye kadar kod aracılığıyla böyle olayı geçen bir yolu var olmayacak.
Yani, sonraki en iyi şey bir dize olarak etkinlik adını geçiş yapmaya çalışan gibiydi: O kadar ideal değil
await FromEvent(new MyClass(), "OnCompletion");
; intellisense alamazsınız ve olay bu tür için mevcut değilse bir çalışma zamanı hatası alırsınız, ancak yine de çok sayıda FromEvent yönteminden daha yararlı olabilir.
nesnesini almak için yansıma veGetEvent(eventName)
kullanmanız yeterli. Bir sonraki problem, o olayın temsilcisinin çalışma zamanında bilinmemesi (ve değişebilmesi gerekmesi). Bu, bir olay işleyicisinin eklenmesi zorlaştırır çünkü çalışma zamanında bir yöntem oluşturmak, zaten sahip olduğumuz ve sonucunu belirleyen bir
TaskCompletionSource
erişen belirli bir imzayı (ancak tüm parametreleri göz ardı ederek) eşleştirmemiz gerekir.
Neyse ki this link'u buldum ve bu sayede [neredeyse] tam olarak Reflection.Emit
aracılığıyla nasıl yapılacağına dair yönergeleri içerir. Şimdi sorun, IL yayamamamız ve benim sahip olduğum tcs
örneğine nasıl erişeceğimize dair bir fikrim yok.
public static Task FromEvent<T>(this T obj, string eventName)
{
var tcs = new TaskCompletionSource<object>();
var eventInfo = obj.GetType().GetEvent(eventName);
Type eventDelegate = eventInfo.EventHandlerType;
Type[] parameterTypes = GetDelegateParameterTypes(eventDelegate);
DynamicMethod handler = new DynamicMethod("unnamed", null, parameterTypes);
ILGenerator ilgen = handler.GetILGenerator();
//TODO ilgen.Emit calls go here
Delegate dEmitted = handler.CreateDelegate(eventDelegate);
eventInfo.AddEventHandler(obj, dEmitted);
return tcs.Task;
}
IL muhtemelen bu beni TaskCompletionSource
sonucunu ayarlamak için izin verecek yayarlar ne olabilir: Aşağıda
BCL'nin 'TaskFactory.FromAsync' adlı dosyayı APM'den TAP'a kolayca çevirebileceğini unutmayın. EAP'tan TAP'a çevirmenin kolay ve genel bir yolu yoktur, bu yüzden MS'nin böyle bir çözüm içermediğini düşünüyorum. Rx (veya TPL Dataflow) 'nu "event" semantiği ile daha yakın bir eşleşme olarak buluyorum ve Rx * 'nin bir' FromEvent' yöntemi vardır. –
Ayrıca, bir "FromEvent <>" jenerik yapmak istedim ve [this] (http://stackoverflow.com/a/22798789/1768303), yansımayı kullanmadan ona ulaşabileceğim kadar yakın. – Noseratio