2011-10-14 19 views
8

साथ interoperate कर रहे हैं आरएक्स टीम Bart De Smet: Rx Update - .NET 4.5, Async, WinRT द्वारा नवीनतम वीडियो में मैंने देखा कि WinRT घटनाओं वास्तव में कुछ अजीब मेटाडाटा, अधिक preciesly द्वारा नेट से अवगत कराया - add_/remove_ जोड़ी तरीकों हस्ताक्षर:कैसे WinRT घटनाओं नेट

EventRegistrationToken add_MyEvent(EventHandler<MyEventArgs> handler) { … } 
void remove_MyEvent(EventRegistrationToken registrationToken) { … } 

यह वास्तव में बहुत अच्छा लग रहा है, पंजीकरण टोकन "निपटान" द्वारा घटना से सदस्यता रद्द करने की अनुमति देता है (आरएक्स एक ही तरह की चीज करता है, विधि Subscribe() विधि से उदाहरण देता है)। इसलिए घटनाओं से लैम्बा-अभिव्यक्तियों को आसानी से सदस्यता लेना संभव हो गया है, लेकिन ...

तो सी # इस तरह की घटनाओं के साथ काम करने की अनुमति कैसे देता है? .NET में प्रतिनिधि पर एक उदाहरण के साथ एक विधि (स्थिर और उदाहरण) की सदस्यता लेना संभव है और पूरी तरह से एक और प्रतिनिधि उदाहरण के साथ सदस्यता समाप्त करने के लिए एक ही विधि की ओर इशारा किया गया है। इसलिए यदि मैं एक WinRT ईवेंट का उपयोग कर रहा हूं और सी # में कुछ प्रतिनिधि प्रकार के उदाहरण की सदस्यता रद्द कर रहा हूं ... कंपाइलर को सही EventRegistrationToken कहां मिला? यह जादू कैसे काम करता है?

- - अद्यतन

असल EventRegistrationToken कि वास्तव में उदासी है, Dispose() विधि किसी तरह का फोन करके बस सदस्यता समाप्त करने की अनुमति नहीं देता:

public struct EventRegistrationToken 
{ 
    internal ulong Value { get; } 
    internal EventRegistrationToken(ulong value) 
    public static bool operator ==(EventRegistrationToken left, EventRegistrationToken right) 
    public static bool operator !=(EventRegistrationToken left, EventRegistrationToken right) 
    public override bool Equals(object obj) 
    public override int GetHashCode() 
} 

- Update2 -

विनरेट इंटरऑपरेबिलिटी वास्तव में वैश्विक रजिस्ट्रार की तालिका का उपयोग करता है प्रबंधित ओबेट्स के साथ WinRT घटनाओं की सदस्यता लेने पर टियन टोकन। उदाहरण के लिए, हैंडलर को हटाने के लिए इंटरऑप कोड इस तरह दिखता है:

internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler) 
{ 
    object target = removeMethod.Target; 
    var eventRegistrationTokenTable = WindowsRuntimeMarshal.ManagedEventRegistrationImpl.GetEventRegistrationTokenTable(target, removeMethod); 
    EventRegistrationToken obj2; 
    lock (eventRegistrationTokenTable) 
    { 
    List<EventRegistrationToken> list; 
    if (!eventRegistrationTokenTable.TryGetValue(handler, out list)) return; 
    if (list == null || list.Count == 0) return; 
    int index = list.Count - 1; 
    obj2 = list[index]; 
    list.RemoveAt(index); 
    } 
    removeMethod(obj2); 
} 

यह वास्तव में दुख की बात है।

+3

ध्यान दें कि आपके द्वारा वर्णित सब कुछ एक कार्यान्वयन विस्तार है और किसी भी समय बदला जा सकता है। आपको किसी भी व्यवहार पर भरोसा नहीं करना चाहिए जिसे आप इंजीनियर करते हैं। –

उत्तर

14

जब आप जोड़ सकते हैं या इस तरह की एक घटना WinRT के लिए एक प्रतिनिधि को हटाने,:

this.Loaded += MainPage_Loaded; 

this.Loaded -= MainPage_Loaded; 

यह सिर्फ आप सामान्य नेट की घटनाओं के साथ काम कर रहे थे लग रहा है। लेकिन इस कोड वास्तव में कुछ इस तरह के संकलित (परावर्तक कुछ परेशानी decompiling WinRT कोड के लिए लगता है, लेकिन मुझे लगता है यह है कि क्या वास्तव में कोड करता है):

WindowsRuntimeMarshal.AddEventHandler<RoutedEventHandler>(
    new Func<RoutedEventHandler, EventRegistrationToken>(this.add_Loaded), 
    new Action<EventRegistrationToken>(remove_Loaded), 
    new RoutedEventHandler(this.MainPage_Loaded)); 

WindowsRuntimeMarshal.RemoveEventHandler<RoutedEventHandler>(
    new Action<EventRegistrationToken>(this.remove_Loaded), 
    new RoutedEventHandler(this.MainPage_Loaded)); 

इस कोड को वास्तव में संकलन नहीं होगा, क्योंकि आप कर सकते हैं सी # से add_ और remove_ विधियों तक पहुंच नहीं है। लेकिन आप इसे आईएल में कर सकते हैं, और यही वह है जो संकलक करता है।

ऐसा लगता है कि WindosRuntimeMarshal उन सभी EventRegistrationToken एस रखता है और आवश्यक होने पर उन्हें सदस्यता समाप्त करने के लिए उपयोग करता है।

+0

ओह नहीं, ऐसा लगता है कि यह वास्तव में प्रबंधित वस्तुओं से सभी सब्सक्राइबियों की ** वैश्विक तालिका ** रखता है ... – ControlFlow

+0

एमएसडीएन के बारे में [कस्टम घटनाओं और विंडोज रनटाइम घटक में ईवेंट एक्सेसर्स] पर एक बहुत अच्छा लेख है (http://msdn.microsoft.com/en-us/library/windows/apps/hh972883.aspx)। @ एसविक, आप – FriendlyGuy

9

क्या आप स्वीकार करेंगे कि "कुछ आश्चर्यजनक चालाक लोग सी # भाषा प्रक्षेपण पर काम कर रहे हैं" एक उत्तर के रूप में?

अधिक गंभीरता से, आपने जो खोजा है वह घटना पैटर्न के निम्न स्तर एबीआई (बाइनरी) कार्यान्वयन है, सी # भाषा प्रक्षेपण इस पैटर्न को जानता है और सी # घटनाओं के रूप में इसका खुलासा करने के बारे में जानता है। सीएलआर के अंदर कक्षाएं हैं जो इस मानचित्रण को लागू करती हैं।

+1

से बहुत दूर नहीं थे सी # WinRT टीम सुअर पर लिपस्टिक डालने की तरह लगता है :) –

+4

क्यों एक सुअर पर लिपस्टिक? यह बिल्कुल सही है कि भाषा अनुमान कैसे काम करते हैं। विंडोज रनटाइम में एक इवेंटिंग पैटर्न होता है (और एक एसिंक पैटर्न और संग्रह पैटर्न और अन्य पैटर्न)। घटनाओं को उजागर करने वाली प्रत्येक एपीआई एक ही पैटर्न का उपयोग करती है। एक भाषा प्रक्षेपण का काम एपीआई लेने के लिए है जो उस पैटर्न का उपयोग करते हैं और उन्हें उस भाषा के उपयोगकर्ताओं के लिए प्राकृतिक और परिचित महसूस करते हैं। विंडोज रनटाइम केवल दो कारणों से सी # इवेंटिंग पैटर्न को अपनाने में सक्षम नहीं था: विंडोज रनटाइम भाषा अज्ञेयवादी होना चाहिए और रनटाइम आजीवन प्रबंधन के लिए संदर्भ गणना का उपयोग करता है। –

+4

दुर्भाग्य से यह भी सही है। घटनाओं के लिए निम्न स्तर का प्रक्षेपण सरल है - एक ईवेंट ऐड और एक इवेंट हटाने की विधि है, ऐड एक प्रतिनिधि लेता है और टोकन देता है, हटाकर टोकन लेता है। जब घटना को निकाल दिया जाता है, तो प्रतिनिधि को बुलाया जाता है। सीएलआर इस निम्न स्तर की तंत्र को सीएलआर संगत संस्करण में मानचित्रित करता है। उपयोग की जाने वाली कक्षाओं के वास्तविक नाम एक कार्यान्वयन विस्तार हैं और एक बिल्ड से दूसरे में परिवर्तन के अधीन हैं। जावास्क्रिप्ट में सी ++ के समान तंत्र का एक पूरी तरह से अलग कार्यान्वयन है। और सभी कार्यान्वयन परिवर्तन के अधीन हैं। –