2011-02-11 10 views
5

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

मैं यह देखना चाहता था कि मेरी समझ सही थी कि डेवलपर के रूप में आपको बिना किसी जांच के घटनाओं को आग लगाना चाहिए कि यह घटना शून्य के बराबर नहीं है? उदाहरण के लिए:

if (this.MyEventThatIWantToFire != null) 
{ 
    this.MyEventThatIWantToFire(); 
} 

सलाह/विचारों के लिए अग्रिम धन्यवाद।

+1

आप सही हैं। – e36M3

+1

हां आपकी समझ सही है। – btlog

+0

इसके अलावा, एक बहुप्रचारित ऐप में आप 'यह। MyEventThatIWantToFire' को एक अस्थायी चर में संग्रहीत करने से पहले और अंततः इसे बढ़ाएंगे ताकि ईवेंट को आपके चेक और आपके raise के बीच अनदेखा होने से रोका जा सके। – deepee1

उत्तर

10

आपके द्वारा दिखाया गया पैटर्न बहु-थ्रेडेड वातावरण में टूटा हुआ है। MyEventThatIWantToFire परीक्षण के बाद शून्य हो सकता है लेकिन आमंत्रण से पहले। यहाँ एक सुरक्षित तरीका है: जब तक आप स्मृति बाधा के कुछ तरह उपयोग करते हैं, तो कोई गारंटी नहीं है

EventHandler handler = MyEventThatIWantToFire; 
if (handler != null) 
{ 
    handler(...); 
} 

ध्यान दें कि आप ग्राहकों की नवीनतम समूह दिखाई देगा, यहां तक ​​कि स्पष्ट रेस स्थिति अनदेखी।

लेकिन हाँ, जब तक कि आप जानते हैं कि यह शून्य नहीं होगा, आपको चेक करने या आपके लिए चेक करने के लिए एक सहायक विधि का उपयोग करने की आवश्यकता है। वहाँ हमेशा एक ग्राहक है सुनिश्चित करने के

एक तरह से नो-सेशन ग्राहक खुद के, उदा जोड़ने के लिए है

public event EventHandler MyEventThatIWantToFire = delegate {}; 

बेशक

, घटनाओं नहीं सरल प्रतिनिधि क्षेत्रों के साथ लागू किया जाना है है। उदाहरण के लिए, के साथ शुरू करने के लिए एक खाली सूची का उपयोग करके List<EventHandler> द्वारा समर्थित एक ईवेंट हो सकता है। हालांकि यह काफी असामान्य होगा। क्योंकि घटना ही तरीके (जोड़ें/निकालें) का सिर्फ एक जोड़ी है

एक घटना ही है, कभी नहीं रिक्त है। अधिक जानकारी के लिए मेरे article about events and delegates देखें।

+0

skeeeeeet। इस बिंदु पर आपके पास स्टॉक ब्लर्ब के साथ इन प्रकार के प्रश्नों को स्वचालित करने के लिए संभवतः स्क्रिप्ट सेट की गई हैं। – x0n

+1

मदद के लिए सभी के लिए बहुत बहुत धन्यवाद! –

0

सी में हाँ # अगर एक घटना कोई प्रतिनिधियों है, यह अशक्त, हो जाएगा तो आप

0

जांच करना चाहिए हाँ, आप की जांच करना चाहिए कि क्या घटना अशक्त नहीं है। अधिकांशतः आपको संरक्षित विधि का सामना करना पड़ता है जो चेक करता है और ईवेंट को आमंत्रित करता है, या यहां तक ​​कि घटना तर्क भी बनाता है। इस तरह कुछ:

public event EventHandler Foo; 

protected void OnFoo() { 
    if (Foo == null) 
     return; 

    Foo(this, new EventArgs()); 
} 

यह दृष्टिकोण आपके व्युत्पन्न वर्गों को घटना (या इनवॉकिंग को रोकने) को रोकने के लिए भी कम करता है।

+1

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

4

आप इसे उस तरह से नहीं करना चाहिए - अगर किसी को जहां एक श्रोता के बीच अगर और दूर करने के लिए घटना के लिए कॉल आप एक अपवाद मिल चाहते हैं।

protected void RaiseEvent() 
{ 
    var handler = Event; 

    if(handler != null) 
     handler(this, EventArgs.Empty); 
} 
बेशक

, इस शायद एक श्रोता कि पहले से ही स्थानीय चर के सृजन और हैंडलर के लिए कॉल के बीच हटा दिया गया था बुला का नुकसान है: यह एक स्थानीय चर के साथ इसका इस्तेमाल करने की अच्छी आदत है।

3

हां, आपको इसे शून्य के लिए जांचना चाहिए, लेकिन जिस तरह से आप इसे कर रहे हैं, वह दौड़ की स्थिति की ओर जाता है।यह संभव है कि अगर कोई व्यक्ति आपके "अगर" और आपके ईवेंट के बीच में अंतिम प्रतिनिधि का सदस्यता रद्द कर लेता है तो यह घटना शून्य हो सकती है। यह करने के लिए स्वीकार किए जाते हैं जिस तरह की तरह है:

public event EventHandler MyEventThatIWantToFire = delegate {}; 

मेक भावना:

var temp = this.MyEventThatIWantToFire; 
if (temp != null) { 
    this.temp(this, EventArgs.Empty); 
} 

या वैकल्पिक रूप से, वहाँ हमेशा इस तरह से अपनी घटना की घोषणा के द्वारा मंगलाचरण सूची में कम से कम एक प्रतिनिधि है सुनिश्चित?

1

हां, आपकी समझ सही है। इसे कॉल करने से पहले प्रतिनिधि के मूल्य की जांच करना आपके ऊपर निर्भर है।

अधिकांश प्रतिनिधि - कौन सी घटनाएं हैं - "बहु-कलाकार" प्रतिनिधि हैं। इसका अर्थ यह है कि एक प्रतिनिधि एक या अधिक तरीकों की सूची प्रबंधित कर सकता है जिसे सक्रिय होने पर कॉल किया जाएगा।

जब प्रतिनिधि null मान का मूल्यांकन करता है, तो कोई पंजीकृत विधि नहीं होती है; इसलिए, कॉल करने के लिए कुछ भी नहीं है। यदि यह null मान के अलावा किसी अन्य चीज़ का मूल्यांकन करता है, तो कम से कम एक विधि पंजीकृत है। प्रतिनिधि को कॉल करना एक पंजीकृत निर्देश है जिसे उसने पंजीकृत किया है। विधियों को कोई गारंटीकृत आदेश में नहीं कहा जाता है।

अतिरिक्त-असाइनमेंट ऑपरेटर (+=) या अतिरिक्त ऑपरेटर (+) का उपयोग करके प्रतिनिधि की विधियों की सूची में एक विधि जोड़ती है। घटाव-असाइनमेंट ऑपरेटर (-=) या घटाव ऑपरेटर (-) का उपयोग प्रतिनिधि की सूची की विधियों से एक विधि को हटा देता है।

यह भी ध्यान दें कि कॉलर के धागे से बुलाए गए विधियों को निष्पादित किया जाता है। यह महत्वपूर्ण है यदि आप अपने उपयोगकर्ता इंटरफ़ेस नियंत्रण को अपडेट करने के लिए ईवेंट का उपयोग कर रहे हैं। इस स्थिति में, आपके नियंत्रण की InvokeRequired संपत्ति का उपयोग आपको क्रॉस-थ्रेडिंग कॉल (Invoke() या BeginInvoke() का उपयोग करके) को शानदार तरीके से प्रबंधित करने देता है।