2008-10-16 12 views
12

कोड से पहले कुछ पाठ ताकि प्रश्न सारांश उलटा नहीं जा सके।किसी घटना के लिए किसी को सब्सक्राइब क्यों किया जाना चाहिए?

class Tree 
{ 
    public event EventHandler MadeSound; 

    public void Fall() { MadeSound(this, new EventArgs()); } 

    static void Main(string[] args) 
    { 
     Tree oaky = new Tree(); 
     oaky.Fall(); 
    } 
} 

मैं सी # में ज्यादा घटनाओं उपयोग नहीं किया है, लेकिन तथ्य यह है कि यह एक NullRefEx का कारण होता है अजीब लगता है। EventHandler संदर्भ को शून्य माना जाता है क्योंकि वर्तमान में इसमें कोई सबस्क्राइबर नहीं है - लेकिन इसका मतलब यह नहीं है कि घटना नहीं हुई है, है ना?

इवेंट हैंडलर मानक प्रतिनिधियों से ईवेंट कीवर्ड द्वारा अलग-अलग होते हैं। भाषा डिजाइनरों ने उन्हें शून्य में चुपचाप क्यों आग नहीं लगाई जब उनके पास कोई ग्राहक नहीं था? (मैं इकट्ठा करता हूं कि आप स्पष्ट रूप से एक खाली प्रतिनिधि जोड़कर इसे मैन्युअल रूप से कर सकते हैं)।

+1

बहुत बढ़िया उदाहरण! उदाहरण के लिए –

+0

भी +1। मुझे लगता है कि एक अकेला जंगल में गिरने से मेडसाउंड आग नहीं होगी। – OregonGhost

+0

जब एक पेड़ जंगल में गिरता है और कोई भी सुन नहीं रहा है, तब भी यह एक आवाज बनाता है - यह कहता है "म्यू" –

उत्तर

3

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

+0

मुझे नहीं लगता कि यह सिर्फ चर का जिक्र कर रहा है, क्योंकि सी # कक्षाओं को अपनी घटनाओं को इस तरह से बदलने की इजाजत नहीं देता है कि यह चर को कुशलतापूर्वक उपयोग करता है।उदाहरण के लिए, सी # "someEvent + = someDeletate;" की अनुमति देगा, लेकिन मुझे नहीं लगता कि यह "someEvent = someEvent + someDelegate" की अनुमति देगा। यह देखते हुए, मैं इस बात से परेशान हूं कि एक प्रतिनिधि को आविष्कार करने के समान वाक्य में एक घटना का उपयोग क्यों नहीं किया जाता है, जिसे "प्रतिनिधि को पकड़ो, और अगर शून्य नहीं है" के रूप में कोडित नहीं किया जाता है। दूसरी ओर, अगर मेरे ड्रूटर थे, तो घटनाएं मल्टीकास्ट प्रतिनिधियों से किसी भी तरह से एक अलग तंत्र का उपयोग करेंगी। – supercat

+0

@supercat एक सी # घटना 'घटना' कीवर्ड के साथ सिर्फ एक प्रतिनिधि है। यह आपके द्वारा वर्णित विशेष पहुंच प्रतिबंध प्रदान करता है लेकिन यह सिर्फ एक वर्ग_ है। – Gusdor

+0

@ गुस्डोर: नहीं, यह नहीं है * नहीं * "सिर्फ एक प्रतिनिधि" संपत्ति से कहीं अधिक "केवल एक फ़ील्ड" है। एक घटना विधियों की एक जोड़ी है, प्रभावी ढंग से: एक सदस्यता लेने के लिए और एक सदस्यता समाप्त करने के लिए। किस तरह से "बस एक वर्ग" है? –

6

ठीक है, विहित रूप है:

void OnMadeSound() 
{ 
    if (MadeSound != null) 
    { 
     MadeSound(this, new EventArgs()); 
    } 
} 

public void Fall() { OnMadeSound(); } 

जो बहुत थोड़ा तेजी से कि एक खाली प्रतिनिधि बुला, इसलिए गति प्रोग्रामिंग सुविधा से अधिक की जीत हुई।

+0

मुझे लगता है कि यह अनुशंसा की जाती है कि ऑन * विधि किसी व्युत्पन्न वर्ग को घटना पर प्रतिक्रिया करने या ईवेंट को कैसे या कब बदला जाए, बदलने के लिए संरक्षित किया गया है। बस एक जोड़ा के रूप में। – OregonGhost

+0

वास्तव में, सबसे सुरक्षित रूप यह है: संरक्षित शून्य ऑनमेडसाउंड() { EventHandler tempHandler = MadeSound; अगर (tempHandler! = Null) { tempHandler (यह, नया EventArgs()); } } –

+0

विधि को संरक्षित किया जाना चाहिए और tempHandler संभावना को रोकता है कि एक NullReferenceException तब होता है जब हैंडलर को शून्य जांच के बीच हटा दिया जाता है और वास्तव में ईवेंट को बढ़ाया जाता है। –

3

बहुत ज़ेन, आह?

जब आप एक घटना को बढ़ाने के लिए चाहते हैं अशक्त के लिए परीक्षण करने के लिए है:

protected void OnMyEvent() 
{ 
    if (this.MyEvent != null) this.MyEvent(this, EventArgs.Empty); 
} 

यह अच्छा होगा यदि आप इस के साथ परेशान करने के लिए नहीं था होगा, लेकिन उन्हें टूटता है।

+0

कूल, EventArgs.Empty :) – xyz

2

जेम्स ने एक अच्छी तकनीकी तर्क प्रदान की, मैं यह भी जोड़ना चाहूंगा कि मैंने लोगों को यह लाभ का उपयोग किया है, अगर कोई ग्राहक किसी ईवेंट को सुन नहीं रहा है, तो वे कोड या कुछ समान में लॉग इन करने के लिए कार्रवाई करेंगे। एक सरल उदाहरण, लेकिन इस संदर्भ में फिटिंग।

2

यदि कोई भी सुन रहा है तो कोई ईवेंट उठाने का क्या मतलब है? तकनीकी रूप से, यह कैसे सी # इसे लागू करने के लिए चुना।

सी # में, एक कार्यक्रम कुछ विशेष पंखों वाला एक प्रतिनिधि होता है। इस मामले में एक प्रतिनिधि को फ़ंक्शन पॉइंटर्स (ग्राहकों के हैंडलर विधियों के लिए) की एक लिंक्ड सूची के रूप में देखा जा सकता है। जब आप 'घटना को आग लगाते हैं' तो प्रत्येक फ़ंक्शन पॉइंटर को बदले में बुलाया जाता है। शुरुआत में प्रतिनिधि किसी और चीज की तरह एक शून्य वस्तु है। जब आप पहली सब्सक्राइब एक्शन के लिए + = करते हैं, तो प्रतिनिधि। कॉम्बाइन कहा जाता है जो सूची को तुरंत चालू करता है। (कॉलिंग null.Invoke() शून्य अपवाद फेंकता है - जब ईवेंट निकाल दिया जाता है।)

यदि आपको अभी भी लगता है कि "यह नहीं होना चाहिए", एक सहायक वर्ग घटनाक्रम हेल्पर का उपयोग करें जैसा कि पुराने और बेहतर 'रक्षात्मक घटना के साथ यहां बताया गया है) प्रकाशन 'http://weblogs.asp.net/rosherove/articles/DefensiveEventPublishing.aspx

4

एक और अच्छा तरीका मैं अशक्त के लिए जाँच करने के लिए याद करने के लिए बिना इस के आसपास पाने के लिए, देखा है:

class Tree 
{ 
    public event EventHandler MadeSound = delegate {}; 

    public void Fall() { MadeSound(this, new EventArgs()); } 

    static void Main(string[] args) 
    { 
     Tree oaky = new Tree(); 
     oaky.Fall(); 
    } 
} 

नोट गुमनाम प्रतिनिधि - शायद एक मामूली प्रदर्शन हिट है, तो आप के लिए है पता लगाएं कि कौन सी विधि (शून्य, या खाली प्रतिनिधि के लिए जाँच करें) आपकी स्थिति में सबसे अच्छा काम करती है।

+0

आपका कोड अभी भी मेडसाउंड को शून्य पर सेट कर सकता है, इसलिए आप अभी भी एक NullReferenceException प्राप्त कर सकते हैं, प्रतिनिधि को {} व्यर्थ –

+0

बनाते हैं या इसे शून्य पर सेट करने के बजाय, आप इसे {} को प्रतिनिधि बनाने के लिए सेट कर सकते हैं ... कितनी बार करते हैं आप एक घटना को शून्य पर सेट करते हैं? मुझे अभी तक अभी तक नहीं मिला है। –

0

प्रतिक्रियाओं के लिए धन्यवाद।मैं समझता हूं कि NullReferenceException क्यों होता है और इसके आसपास कैसे जाना है।

Gishu

अगर कोई सुन रहा है एक घटना को ऊपर उठाने की बात क्या है कहा?

ठीक है, शायद यह एक शब्दावली बात है। एक "घटना" प्रणाली की अपील मुझे लगता है कि घटना के पतन के सभी जिम्मेदारियों को देखने वालों पर होना चाहिए, न कि कलाकार।


शायद पूछने के लिए बेहतर होते हैं:

MadeSound(this, EventArgs.Empty) 

करने के लिए: एक प्रतिनिधि क्षेत्र के सामने घटना कीवर्ड के साथ घोषित किया जाता है, तो क्यों संकलक के सभी उदाहरणों अनुवाद नहीं करता है
if (MadeSound != null) { MadeSound(this, EventArgs.Empty); } 

दृश्यों के पीछे अन्य सिंटैक्स शॉर्टकट्स हैं? बॉयलरप्लेट ऑनसोमवेन्ट नल जांच विधियों की संख्या जिन्हें लोगों को मैन्युअल रूप से लिखना है, वे विशाल होना चाहिए।

+0

कंपाइलर यह अलग कर रहा है कि यह एक ही पहलू में क्या कर रहा है - एक चर और एक ही नाम के साथ एक घटना बनाना। जटिलता के लिए, मैं इसके बजाय ऐसा नहीं करता था। शून्य जांच से बचना आसान है हालांकि: सार्वजनिक घटना EventHandler क्लिक = प्रतिनिधि {}; –

+0

तो कक्षा के बाहर से, मेडसाउंड एक "घटना" को संदर्भित करता है, जो इवेंट हैंडलर प्रतिनिधि के उदाहरण के लिए उपयुक्त प्रतिनिधियों को जोड़ने/हटाने का प्रबंधन करता है जो समान पहचानकर्ता साझा करता है और आंतरिक रूप से "ईवेंट" को छुपाता है? मतलब यह है कि घटना को सीधे नहीं निकाल दिया जाता है, बल्कि प्रतिनिधि सूची का उत्पादन किया जाता है? – xyz

+0

@ जोन मैं असहमत हूं। मुझे आपके लिए बहुत सम्मान है लेकिन यह देखने में असफल रहा कि आप प्रतिनिधि {} प्रारंभकर्ता पैटर्न का समर्थन क्यों करेंगे। –

4

सिफारिश पैटर्न (.net 2.0+)

public class MyClass 
{ 
    public event EventHandler<EventArgs> MyEvent; // the event 

    // protected to allow subclasses to override what happens when event raised. 
    protected virtual void OnMyEvent(object sender, EventArgs e) 
    { 
     // prevent race condition by copying reference locally 
     EventHandler<EventArgs> localHandler = MyEvent; 
     if (localHandler != null) 
     { 
      localHandler(sender, e); 
     } 
    } 
    public void SomethingThatGeneratesEvent() 
    { 
     OnMyEvent(this, EventArgs.Empty); 
    } 
} 

है मैं एक खाली प्रतिनिधि {} एक प्रारंभकर्ता में के लिए सिफारिशें की एक बहुत कुछ देखते हैं, लेकिन मैं पूरी तरह इससे असहमत हैं। यदि आप उपर्युक्त पैटर्न का पालन करते हैं तो आप केवल एक ही स्थान पर event != null देखें। खाली प्रतिनिधि {} प्रारंभकर्ता एक अपशिष्ट है क्योंकि यह प्रति ईवेंट एक अतिरिक्त कॉल है, यह स्मृति को बर्बाद कर देता है, और अगर मेरी कक्षा में MyEvent को कहीं और शून्य पर सेट किया गया है तो यह अभी भी असफल हो सकता है।

* यदि आपकी कक्षा सील कर दी गई है, तो आप OnMyEvent() आभासी नहीं बनायेंगे।

1

एक विस्तार विधि का उपयोग इस परिदृश्य में सहायक होगा।

public static class EventExtension 
{ 
    public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs 
    { 
     if (handler != null) 
     { 
      handler(obj, args); 
     } 
    } 
} 

इसका उपयोग नीचे जैसा किया जा सकता है।

public event EventHandler<YourEventArgs> YourEvent; 
... 
YourEvent.RaiseEvent(this, new YourEventArgs()); 
+0

धन्यवाद। मैं वास्तव में उस दृष्टिकोण पर आया और सादे पुराने EventArgs के लिए भी एक बनाया :) – xyz

संबंधित मुद्दे

 संबंधित मुद्दे