नया एसिंक/प्रतीक्षा मॉडल का उपयोग करना Task
उत्पन्न करने के लिए यह काफी सरल है जो किसी ईवेंट को आग लगने पर पूरा हो जाता है;सामान्य उद्देश्य FromEvent विधि
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;
}
यह तो अनुमति देता है::
await FromEvent(new MyClass());
समस्या यह है कि आप हर कक्षा में हर घटना है कि आप await
चाहते हैं के लिए एक नया FromEvent
विधि बनाने की जरूरत है आप सिर्फ इस पैटर्न का पालन करने की जरूरत है पर। यह वास्तव में वास्तव में बहुत तेज़ हो सकता है, और यह वैसे भी बॉयलरप्लेट कोड है।
आदर्श रूप में मैं इस तरह कुछ करने के लिए सक्षम होने के लिए करना चाहते हैं:
await FromEvent(new MyClass().OnCompletion);
तो मैं कर सकता है एक ही FromEvent
विधि किसी भी घटना पर किसी भी घटना के लिए फिर से इस्तेमाल करते हैं। मैंने इस तरह की एक विधि बनाने की कोशिश करने में कुछ समय बिताया है, और कई स्नैग हैं। के लिए यह ऊपर कोड निम्न त्रुटि उत्पन्न करेगा: जहां तक मेरा बता सकते हैं
The event 'Namespace.MyClass.OnCompletion' can only appear on the left hand side of += or -=
, वहाँ कभी कोड के माध्यम से इस तरह घटना पास करने का तरीका नहीं होगा।
तो, अगली सबसे अच्छी बात एक स्ट्रिंग के रूप घटना नाम पारित करने के लिए कोशिश कर लग रहा था:
await FromEvent(new MyClass(), "OnCompletion");
यह रूप में आदर्श नहीं है; आपको इंटेलिजेंस नहीं मिलता है और यदि रन उस प्रकार के लिए मौजूद नहीं है, तो यह रनटाइम त्रुटि प्राप्त करेगा, लेकिन यह अभी भी FromEvent विधियों के टन से अधिक उपयोगी हो सकता है।
तो EventInfo
ऑब्जेक्ट प्राप्त करने के लिए प्रतिबिंब और GetEvent(eventName)
का उपयोग करना काफी आसान है। अगली समस्या यह है कि उस घटना के प्रतिनिधि को रनटाइम पर ज्ञात नहीं है (और अलग-अलग करने में सक्षम होना चाहिए)। इससे इवेंट हैंडलर को कड़ी मेहनत मिलती है, क्योंकि हमें रनटाइम पर गतिशील रूप से एक विधि बनाने की आवश्यकता होती है, किसी दिए गए हस्ताक्षर से मिलान करना (लेकिन सभी पैरामीटर को अनदेखा करना) जो TaskCompletionSource
तक पहुंचता है जो हमारे पास पहले से है और उसका परिणाम सेट करता है।
सौभाग्य से मुझे this link मिला जिसमें [लगभग] वास्तव में Reflection.Emit
के माध्यम से निर्देशों के बारे में निर्देश शामिल हैं। अब समस्या यह है कि हमें आईएल उत्सर्जित करने की आवश्यकता है, और मुझे नहीं पता कि मेरे पास tcs
उदाहरण का उपयोग कैसे किया जाए।
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;
}
क्या आईएल मैं संभवतः फेंकना सकता है कि मुझे TaskCompletionSource
का परिणाम सेट करने की अनुमति होगी:
नीचे प्रगति है कि मैं इस परिष्करण की ओर कर दिया है है? या, वैकल्पिक रूप से, क्या कोई तरीका बनाने के लिए कोई और तरीका है जो किसी मनमानी घटना से किसी मनमानी घटना के लिए कार्य देता है?
ध्यान दें कि बीसीएल में 'TaskFactory.FromAsync' है जो आसानी से एपीएम से टीएपी में अनुवाद करने के लिए है। ईएपी से टीएपी में अनुवाद करने के लिए एक आसान * और * सामान्य तरीका नहीं है, इसलिए मुझे लगता है कि एमएस में इस तरह का समाधान शामिल नहीं था। मुझे आरएक्स (या टीपीएल डेटाफ्लो) किसी भी तरह से "ईवेंट" सेमेन्टिक्स के करीब मिलान करने के लिए मिलता है - और आरएक्स * करता है * एक 'FromEvent' विधि है। –
मैं भी एक सामान्य 'FromEvent <>' बनाना चाहता था, और [यह] (http://stackoverflow.com/a/22798789/1768303) करीब है क्योंकि मैं प्रतिबिंब का उपयोग किए बिना उस पर पहुंच सकता हूं। – Noseratio