क्या कोई ईवेंट हैंडलर पहले ही जोड़ा जा चुका है?


183

क्या यह बताने का कोई तरीका है कि क्या किसी इवेंट हैंडलर को किसी ऑब्जेक्ट में जोड़ा गया है? मैं सत्र राज्य से बाहर / बाहर वस्तुओं की एक सूची को क्रमबद्ध कर रहा हूं ताकि हम SQL आधारित सत्र स्थिति का उपयोग कर सकें ... जब सूची में किसी ऑब्जेक्ट में कोई गुण होता है तो उसे फ़्लैग करने की आवश्यकता होती है, जिसे इवेंट हैंडलर ने ठीक से ध्यान रखा है । हालाँकि अब जब ऑब्जेक्ट डिसेररलाइज़ किए जाते हैं तो यह ईवेंट हैंडलर नहीं होता है।

हल्के झुंझलाहट के एक फिट में, मैंने इवेंट हैंडलर को केवल उस संपत्ति तक पहुंचा दिया जो ऑब्जेक्ट तक पहुंचती है। यह अब कहा जा रहा है जो महान है, सिवाय इसके कि इसे 5 बार कहा जा रहा है, इसलिए मुझे लगता है कि हैंडलर बस हर बार जोड़ा जाता है ताकि ऑब्जेक्ट एक्सेस हो जाए।

यह वास्तव में केवल अनदेखा करने के लिए पर्याप्त सुरक्षित है, लेकिन मैं यह देखना चाहता हूं कि हैंडलर पहले से ही जोड़ा गया है या नहीं, यह देखने के लिए मैं केवल एक बार ऐसा करता हूं।

क्या यह संभव है?

संपादित करें: मैं जरूरी नहीं कि घटना संचालकों को पूरा नियंत्रण है, इसलिए बस अशक्त के लिए जाँच करना पर्याप्त नहीं है।


यह भी देखें stackoverflow.com/questions/367523/…
Ian Ringrose

जवाबों:


123

@Telos उल्लेख के रूप में, परिभाषित करने वाली कक्षा के बाहर से, आप केवल एक +=या एक के बाईं ओर ईवेंटहैंडलर का उपयोग कर सकते हैं -=। इसलिए, यदि आपके पास डिफाइनिंग क्लास को संशोधित करने की क्षमता है, तो आप इवेंट हैंडलर है nullया नहीं, यह चेक करके चेक करने की विधि प्रदान कर सकते हैं - यदि ऐसा है, तो कोई ईवेंट हैंडलर नहीं जोड़ा गया है। यदि नहीं, तो हो सकता है और आप Delegate.GetInvocationList में मूल्यों के माध्यम से लूप कर सकते हैं । यदि कोई उस प्रतिनिधि के बराबर है जिसे आप ईवेंट हैंडलर के रूप में जोड़ना चाहते हैं, तो आप जानते हैं कि यह वहां है।

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{   
    if ( this.EventHandler != null )
    {
        foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
        {
            if ( existingHandler == prospectiveHandler )
            {
                return true;
            }
        }
    }
    return false;
}

और इसे आसानी से संशोधित किया जा सकता है "यदि यह नहीं है तो हैंडलर जोड़ें"। आप वर्ग के धर्मशाला है कि घटना को उजागर कर रहा है के लिए पहुँच नहीं है, तो आप पता लगाने के लिए आवश्यकता हो सकती है -=और +=के रूप में @Lou फ्रेंको ने सुझाव दिया,।

हालाँकि, आप इन चीजों को पुनः प्राप्त करने के तरीके को बेहतर बना सकते हैं और इन वस्तुओं को हटा सकते हैं, यह देखने के लिए कि क्या आप इस जानकारी को ट्रैक करने का कोई तरीका नहीं खोज सकते हैं।


7
यह संकलन नहीं करता है, EventHandler केवल बाईं ओर + = या - = पर हो सकता है।
कोडरेडिक

2
आगे की समझाइश पर वोट हटाया गया। एसक्यूएल राज्य यहाँ पूरे विचार को नष्ट कर रहा है ...:
कोडरेडिक

1
धन्यवाद ब्लेयर और एसओ खोज, बस जो मैं देख रहा था (कष्टप्रद है, हालांकि आप इसे कक्षा के बाहर नहीं कर सकते हैं)
जॉर्ज मौअर

3
समानता के लिए प्रतिनिधियों की तुलना करते समय समस्या अधिकांश समय होती है। इसलिए Delegate.Equals(objA, objB)यदि आप एक ही प्रतिनिधि अस्तित्व के लिए जाँच करना चाहते हैं तो उपयोग करें। अन्यथा गुणों की तुलना व्यक्तिगत रूप से करें if(objA.Method.Name == objB.Method.Name && objA.Target.GetType().FullName == objB.Target.GetType().FullName)
संजय

2
यह कोड WinForm में काम नहीं कर रहा है। यह ASP.NET के लिए सख्ती से है?
jp2code

211

मैं हाल ही में एक ऐसी स्थिति में आया था जहां मुझे केवल एक बार एक घटना के लिए हैंडलर को पंजीकृत करने की आवश्यकता थी। मैंने पाया कि आप सुरक्षित रूप से पहले अपंजीकृत कर सकते हैं, और फिर फिर से पंजीकरण कर सकते हैं, भले ही हैंडलर पंजीकृत न हो:

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;

ध्यान दें कि हर बार जब आप अपने हैंडलर को पंजीकृत करते हैं, तो यह सुनिश्चित करेगा कि आपका हैंडलर केवल एक बार पंजीकृत हो। मेरे लिए एक बहुत अच्छा अभ्यास की तरह लगता है :)


9
जोखिम भरा लगता है; यदि हैंडलर को हटाने के बाद और वापस जोड़ने से पहले किसी घटना को निकाल दिया जाता है, तो यह छूट जाएगा।
जिमी

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

6
यह मुझे परेशान करता है। सिर्फ इसलिए कि आप वर्तमान में अपने कोड में स्पष्ट रूप से थ्रेड नहीं बना रहे हैं, इसका मतलब यह नहीं है कि कई थ्रेड नहीं हैं, या वे बाद में जोड़े नहीं जाएंगे। जैसे ही आप (या किसी और टीम में, संभवतः महीनों बाद) एक कार्यकर्ता धागा जोड़ते हैं या यूआई और नेटवर्क कनेक्शन दोनों का जवाब देते हैं, यह अत्यधिक रुक-रुक कर होने वाली घटनाओं के लिए द्वार खोलता है।
टेक्नोफाइल

1
मेरा मानना ​​है कि हटाने और फिर से जोड़ने के बीच की समय-सीमा इतनी छोटी है, कि छूटी हुई घटनाओं के होने की संभावना बहुत कम है, लेकिन हाँ, यह अभी भी संभव है।
Alisson

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

18

यदि यह एकमात्र हैंडलर है, तो आप यह देखने के लिए देख सकते हैं कि क्या घटना शून्य है, यदि यह नहीं है, तो हैंडलर जोड़ा गया है।

मुझे लगता है कि आप अपने हैंडलर के साथ घटना पर सुरक्षित रूप से कॉल कर सकते हैं - भले ही यह जोड़ा नहीं गया है (यदि नहीं, तो आप इसे पकड़ सकते हैं) - यह सुनिश्चित करने के लिए कि इसमें जोड़ने से पहले नहीं है।


3
जैसे ही घटना कहीं और होगी, यह तर्क टूट जाएगा।
Bugged87

6

यह उदाहरण दिखाता है कि विधि का उपयोग कैसे करें GetInvocationList () को उन सभी हैंडलर को डेलिगेट प्राप्त करने के लिए जो जोड़े गए हैं। यदि आप यह देखना चाह रहे हैं कि क्या कोई विशिष्ट हैंडलर (फ़ंक्शन) जोड़ा गया है तो आप ऐरे का उपयोग कर सकते हैं।

public class MyClass
{
  event Action MyEvent;
}

...

MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;

...

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method

आप यह देखने के लिए कि क्या कोई विशिष्ट फ़ंक्शन जोड़ा गया है, प्रतिनिधि की विधि गुण पर विभिन्न गुणों की जाँच कर सकते हैं।

यदि आप यह देखना चाह रहे हैं कि क्या सिर्फ एक जुड़ी हुई है, तो आप केवल अशक्त होने के लिए परीक्षण कर सकते हैं।


GetInvocationList () मेरी कक्षा का सदस्य नहीं है। वास्तव में, मैं इस विधि को किसी भी वस्तु या हैंडलर पर नहीं खोज पा रहा हूं ...
CodeRedick

मैंने वह भी आजमाया था, जाहिर है कि आप इस तरह की घटना को कक्षा के अंदर से ही देख सकते हैं। मैं यह उदारतापूर्वक कर रहा हूं, और जैसा कि दूसरों ने उल्लेख किया है कि घटना हैंडलर शायद वैसे भी खो रहे हैं। स्पष्टीकरण के लिए धन्यवाद!
कोडरेडिक

4

अगर मैं आपकी समस्या को सही ढंग से समझ पाऊं तो आपके पास बड़े मुद्दे हो सकते हैं। आपने कहा कि अन्य ऑब्जेक्ट इन घटनाओं की सदस्यता ले सकते हैं। जब वस्तु क्रमबद्ध होती है और अन्य वस्तुओं को निष्क्रिय करती है (जिन पर आपका नियंत्रण नहीं है) उनके घटना संचालकों को खो देगी।

यदि आप इसके बारे में चिंतित नहीं हैं तो अपने ईवेंट हैंडलर का संदर्भ रखना काफी अच्छा होना चाहिए। यदि आप अपने ईवेंट हैंडलर को खोने वाली अन्य वस्तुओं के दुष्प्रभावों के बारे में चिंतित हैं, तो आप अपनी कैशिंग रणनीति पर फिर से विचार कर सकते हैं।


1
डी 'ओह! यह भी नहीं सोचा था ... हालांकि यह स्पष्ट होना चाहिए मेरी मूल समस्या पर विचार किया गया था मेरे अपने हैंडलर खो दिया है।
कोडरेडिक

2

मेरे लिए काम करने का एकमात्र तरीका एक बूलियन चर बना रहा है जिसे मैंने घटना को जोड़ने पर सच करने के लिए सेट किया है। फिर मैं पूछता हूं: यदि चर गलत है, तो मैं घटना जोड़ता हूं।

bool alreadyAdded = false;

यह चर वैश्विक हो सकता है।

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}

1

मैं अल्फ के जवाब से सहमत हूं, लेकिन इसका थोड़ा संशोधन करना है ,,,

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }

0
EventHandler.GetInvocationList().Length > 0

2
सूची == अशक्त होने पर यह नहीं फेंकता है?
बोरिस ने

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