घटना हैंडलर निष्पादन का आदेश


93

यदि मैं कई इवेंट हैंडलर सेट करता हूँ, जैसे:

_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;

जब ईवेंट RetrieveDataCompletedको निकाल दिया जाता है तो हैंडलर किस क्रम पर चलते हैं ? क्या वे उसी धागे में चलते हैं और क्रमबद्ध तरीके से पंजीकृत होते हैं?


2
इसका जवाब RetrieveDataCompleted इवेंट के लिए विशिष्ट होगा। यदि इसके पास एक मल्टी-कास्ट डेलीगेट का डिफ़ॉल्ट बैकिंग स्टोर है, तो हाँ "वे उसी धागे में चलते हैं और क्रमबद्ध तरीके से पंजीकृत होते हैं"।
HappyNomad

जवाबों:


131

वर्तमान में, वे उस क्रम में निष्पादित किए जाते हैं जो वे पंजीकृत हैं। हालांकि, यह एक कार्यान्वयन विवरण है, और मैं भविष्य के संस्करणों में समान रहने वाले इस व्यवहार पर भरोसा नहीं करूंगा, क्योंकि विनिर्देशों द्वारा इसकी आवश्यकता नहीं है।


5
मुझे आश्चर्य है, नीचे क्यों? यह बिल्कुल सच है, और सीधे सवाल का जवाब देता है ...
रीड कोपसी

2
@ रॉलिंग: यह बाइनरी ऑपरेटर ओवरलोड रिज़ॉल्यूशन के लिए है - इवेंट हैंडलिंग नहीं। इस मामले में यह अतिरिक्त ऑपरेटर नहीं है।
रीड कोपसे

2
आह, मैं देखता हूं कि मैं कहां गलत हो रहा हूं: "इवेंट हैंडलर प्रतिनिधि हैं, ठीक है?"। मुझे अब पता है कि वे नहीं हैं। अपने आप को एक घटना लिखी है जो हैंडलर को उल्टे क्रम में फायर करती है, बस उसे खुद को साबित करने के लिए :)
रॉलिंग

16
स्पष्ट करने के लिए, आदेश एक विशेष घटना के लिए बैकिंग स्टोर पर निर्भर करता है। घटनाओं के लिए डिफ़ॉल्ट बैकिंग स्टोर, मल्टी-कास्ट डेलीगेट्स, पंजीकरण क्रम में निष्पादित के रूप में प्रलेखित हैं। यह भविष्य के फ्रेमवर्क संस्करण में नहीं बदलेगा। क्या परिवर्तन हो सकता है एक विशेष घटना के लिए इस्तेमाल किया जाने वाला बैकिंग स्टोर।
HappyNomad

6
डाउनवोट किया गया क्योंकि यह 2 बिंदुओं पर तथ्यात्मक रूप से गलत है। 1) वर्तमान में उन्हें इस क्रम में निष्पादित किया जाता है कि विशिष्ट घटना का कार्यान्वयन निर्धारित होता है - चूंकि आप घटनाओं के लिए अपने स्वयं के ऐड / रिमूव तरीकों को लागू कर सकते हैं। 2) जब मल्टी-कास्ट प्रतिनिधियों के माध्यम से डिफ़ॉल्ट ईवेंट कार्यान्वयन का उपयोग किया जाता है, तो आदेश वास्तव में विनिर्देशों द्वारा आवश्यक होता है।
सोरेन बोइसेन

53

एक प्रतिनिधि की मंगलाचरण सूची प्रतिनिधियों का एक सेट किया गया क्रम है जिसमें सूची का प्रत्येक तत्व प्रतिनिधि द्वारा आमंत्रित किए गए तरीकों में से एक को ठीक से आमंत्रित करता है। एक आह्वान सूची में डुप्लिकेट तरीके हो सकते हैं। एक आह्वान के दौरान, एक प्रतिनिधि उस क्रम में तरीकों का आह्वान करता है जिसमें वे मंगलाचरण सूची में दिखाई देते हैं

यहां से: डेलिगेट क्लास


1
अच्छा है, लेकिन एक घटना का उपयोग करते हुए addऔर removeकीवर्ड्स को एक बहु-कलाकारों के प्रतिनिधि के रूप में लागू नहीं किया जा सकता है।
HappyNomad

बॉब के साथ , अन्य जवाबों का उल्लेख है कि इवेंट हैंडलर के साथ इसका उपयोग कुछ ऐसा है जिसे अविश्वसनीय माना जाना चाहिए ... चाहे वह सही हो या नहीं, यह उत्तर उस बारे में भी बात कर सकता है।
n611x007

12

आप सभी हैंडलर को हटाकर ऑर्डर बदल सकते हैं, और फिर वांछित क्रम में पुनः संलग्न कर सकते हैं।

public event EventHandler event1;

public void ChangeHandlersOrdering()
{
    if (event1 != null)
    {
        List<EventHandler> invocationList = event1.GetInvocationList()
                                                  .OfType<EventHandler>()
                                                  .ToList();

        foreach (var handler in invocationList)
        {
            event1 -= handler;
        }

        //Change ordering now, for example in reverese order as follows
        for (int i = invocationList.Count - 1; i >= 0; i--)
        {
            event1 += invocationList[i];
        }
    }
}

10

आदेश मनमाना है। आप किसी भी विशेष क्रम में एक आह्वान से अगले तक निष्पादित किए जाने वाले हैंडलर पर भरोसा नहीं कर सकते।

संपादित करें: और यह भी - जब तक कि यह सिर्फ जिज्ञासा से बाहर न हो - तथ्य यह है कि आपको पता होना चाहिए कि एक गंभीर डिजाइन समस्या का संकेत है।


3
आदेश विशेष घटना के कार्यान्वयन पर निर्भर करता है, लेकिन यह मनमाना नहीं है। जब तक कि घटना का दस्तावेजीकरण मंगलाचरण आदेश को इंगित नहीं करता है, हालांकि, मैं मानता हूं कि इस पर निर्भर होना जोखिम भरा है। उस नस में, मैंने एक अनुवर्ती प्रश्न पोस्ट किया ।
HappyNomad

9
एक घटना है कि एक अलग क्रम में विभिन्न वर्गों द्वारा नियंत्रित किया जाना चाहिए मुझे एक गंभीर डिजाइन समस्या नहीं लगती है। समस्या तब होगी जब ईवेंट पंजीकरण इस तरह से किया जाए जिससे ऑर्डर या इवेंट को जानना मुश्किल हो जाए कि ऑर्डर महत्वपूर्ण है।
इग्नासियो सोलर गार्सिया

8

वे उस क्रम में चलाए जाते हैं जिसमें वे पंजीकृत हैं। RetrieveDataCompletedएक बहुस्त्र्पीय प्रतिनिधि है । मैं कोशिश करने और सत्यापित करने के लिए परावर्तक के माध्यम से देख रहा हूं, और ऐसा लग रहा है कि सब कुछ का ध्यान रखने के लिए एक सरणी का उपयोग पर्दे के पीछे किया जाता है।


अन्य उत्तर ध्यान दें कि घटना संचालकों के साथ यह 'आकस्मिक', 'नाजुक', 'कार्यान्वयन विस्तार', आदि है, अर्थात। किसी भी मानक या सम्मेलन की आवश्यकता नहीं है, यह सिर्फ होता है। क्या वह सही है? किसी भी मामले में, यह उत्तर भी संदर्भित कर सकता है।
n611x007

3

यदि किसी को System.Windows.Forms.Form के संदर्भ में ऐसा करने की आवश्यकता है, तो यहां एक उदाहरण दिखाया गया है जो शोवन ईवेंट के क्रम को बताता है।

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace ConsoleApplication {
    class Program {
        static void Main() {
            Form form;

            form = createForm();
            form.ShowDialog();

            form = createForm();
            invertShownOrder(form);
            form.ShowDialog();
        }

        static Form createForm() {
            var form = new Form();
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown1"); };
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown2"); };
            return form;
        }

        static void invertShownOrder(Form form) {
            var events = typeof(Form)
                .GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(form, null) as EventHandlerList;

            var shownEventKey = typeof(Form)
                .GetField("EVENT_SHOWN", BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(form);

            var shownEventHandler = events[shownEventKey] as EventHandler;

            if (shownEventHandler != null) {
                var invocationList = shownEventHandler
                    .GetInvocationList()
                    .OfType<EventHandler>()
                    .ToList();

                foreach (var handler in invocationList) {
                    events.RemoveHandler(shownEventKey, handler);
                }

                for (int i = invocationList.Count - 1; i >= 0; i--) {
                    events.AddHandler(shownEventKey, invocationList[i]);
                }
            }
        }
    }
}

2

एक मल्टीकास्टडेलेगेट में प्रतिनिधियों की एक लिंक की गई सूची है, जिसे एक या अधिक तत्वों से युक्त एक मंगलाचरण सूची कहा जाता है। जब एक मल्टीकास्ट प्रतिनिधि को आमंत्रित किया जाता है, तो मंगलाचरण सूची में प्रतिनिधियों को उस क्रम में सिंक्रोनस कहा जाता है जिसमें वे दिखाई देते हैं। यदि सूची के निष्पादन के दौरान कोई त्रुटि होती है तो एक अपवाद फेंक दिया जाता है।


2

एक मंगलाचरण के दौरान, विधियाँ उस क्रम में मंगाई जाती हैं, जिसमें वे आह्वान सूची में दिखाई देते हैं।

लेकिन कोई भी नहीं कहता है कि मंगलाचरण सूची उसी क्रम में प्रतिनिधियों को बनाए रखती है जैसे वे जोड़े जाते हैं। इस प्रकार मंगलाचरण की गारंटी नहीं है।


1

यह एक ऐसा फंक्शन है जो मल्टीलेगेट इनवोकेशन लिस्ट में जहां चाहे नया इवेंट हैंडलर फंक्शन देगा।

    private void addDelegateAt(ref YourDelegate initial, YourDelegate newHandler, int position)
    {
        Delegate[] subscribers = initial.GetInvocationList();
        Delegate[] newSubscriptions = new Delegate[subscribers.Length + 1];

        for (int i = 0; i < newSubscriptions.Length; i++)
        {
            if (i < position)
                newSubscriptions[i] = subscribers[i];
            else if (i==position)
                newSubscriptions[i] = (YourDelegate)newHandler;
            else if (i > position)
                newSubscriptions[i] = subscribers[i-1];
        }

        initial = (YourDelegate)Delegate.Combine(newSubscriptions);
    }

तब आप हमेशा अपने कोड में जहाँ भी सुविधाजनक हो '- =' फ़ंक्शन को हटा सकते हैं।

PS - मैं 'स्थिति' पैरामीटर के लिए कोई त्रुटि हैंडलिंग नहीं कर रहा हूँ।


0

मुझे भी ऐसी ही समस्या का समाधान करना पड़ा था। मेरे मामले में यह बहुत आसानी से तय हो गया था। मैंने कभी ऐसा प्रतिनिधि नहीं देखा, जिसने + = ऑपरेटर का उपयोग न किया हो। मेरी समस्या एक प्रतिनिधि द्वारा हमेशा के अंत में जोड़े जाने से तय हुई थी, अन्य सभी को हमेशा शुरुआत में जोड़ा जाता है। ओपी का उदाहरण कुछ इस तरह होगा:

    _webservice.RetrieveDataCompleted = _webservice.RetrieveDataCompleted + ProcessData1;
    _webservice.RetrieveDataCompleted = ProcessData2 + _webservice.RetrieveDataCompleted;

पहले मामले में ProcessData1 को अंतिम कहा जाएगा। दूसरे मामले में ProcessData2 को पहले कहा जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.