घटनाओं को परिभाषित करते समय हमें "ईवेंट" कीवर्ड की आवश्यकता क्यों है?


109

मुझे समझ में नहीं आता कि घटनाओं को परिभाषित करते समय हमें "ईवेंट" कीवर्ड की आवश्यकता क्यों है, जब हम "इवेंट" कीवर्ड का उपयोग किए बिना एक ही काम कर सकते हैं, केवल प्रतिनिधियों का उपयोग करके।

जैसे

public delegate void CustomEventHandler(int a, string b);
public event CustomEventHandler customEvent;
customEvent += new CustomEventHandler(customEventHandler);
customEvent(1,"a"); // Raising the event

यहां यदि मैं दूसरी पंक्ति से "ईवेंट" कीवर्ड हटाता हूं, तो मैं भी प्रतिनिधि को आमंत्रित करके घटना को बढ़ा सकता हूं। क्या कोई मुझे बता सकता है कि इस ईवेंट कीवर्ड की आवश्यकता क्यों है?


यदि आप इवेंट कीवर्ड का उपयोग नहीं करते हैं तो ठीक है जो क्लास ऑब्जेक्ट का उपयोग करके उस ईवेंट को एक्सेस कर सकता है जो इसे objClass.SelectedIndexChanged = null की तरह सेट करता है। इससे आपका अंतर्निहित कोड क्रैश हो जाएगा। ईवेंट कीवर्ड उपयोगकर्ता को = = का उपयोग करके प्रतिनिधि के समान कुछ असाइन करने के लिए लागू करता है।
सुमित कपाड़िया

जवाबों:


142

फील्ड-जैसी घटनाएं और प्रतिनिधि प्रकार के सार्वजनिक क्षेत्र समान दिखते हैं , लेकिन वास्तव में बहुत अलग हैं।

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

घटनाओं के बारे में अधिक जानकारी के लिए (और प्रतिनिधियों) ने इस विषय पर मेरा लेख पढ़ा । (कुछ बिंदु पर मुझे इसे C # 4 के लिए अपडेट करने की आवश्यकता है, जो फ़ील्ड जैसी घटनाओं को बहुत कम बदल देता है। इसके बारे में जानकारी अभी भी सही है।)


17
यह MSDN की आधिकारिक एक-पंक्ति स्पष्टीकरण की तुलना में एक हजार गुना बेहतर है: 'ईवेंट कीवर्ड का उपयोग किसी पब्लिशर वर्ग में किसी घटना को घोषित करने के लिए किया जाता है।'
सहकर्मी

37

इवेंट कीवर्ड 3 अलग चीजें करता है:

  1. आप किसी ईवेंट को इंटरफ़ेस में परिभाषित कर सकते हैं, भले ही आप इंटरफ़ेस में नियमित फ़ील्ड को परिभाषित नहीं कर सकते।
  2. यह =और ()ऑपरेटरों (असाइनमेंट और इनवोकेशन) की दृश्यता को निजी में बदल देता है, ताकि केवल शामिल वर्ग ही ईवेंट को लागू कर सके या उसमें मौजूद सभी तरीकों को ओवरराइड कर सके। -=और +=ऑपरेटरों अभी भी वर्ग परिभाषित (वे मिल पहुँच संशोधक आपको ईवेंट के आगे लिखा था) बाहर से एक घटना पर लागू किया जा सकता है।
  3. आप रास्ते को ओवरराइड भी कर सकते हैं -=और +=घटनाओं पर व्यवहार कर सकते हैं।

2
आप> MSDN। धन्यवाद।
एम। अज़िओक्सुल

26

अन्य उत्तर ठीक हैं; मैं सिर्फ सोचने के लिए कुछ और जोड़ना चाहूंगा।

आपका सवाल यह है कि "जब हमें प्रतिनिधि प्रकार के क्षेत्र हैं, तो हमें घटनाओं की आवश्यकता क्यों है?" मैं उस प्रश्न का विस्तार करूंगा: यदि आपके पास डेलिगेट प्रकार के क्षेत्र हैं, तो आपको विधियों, गुणों, घटनाओं, उदाहरण के निर्माणकर्ताओं या फाइनलर्स की आवश्यकता क्यों है? आपको फ़ील्ड के अलावा किसी अन्य चीज़ की आवश्यकता क्यों है जिसमें एक प्रकार में मान और प्रतिनिधि होते हैं? सिर्फ क्यों नहीं कहते

class C
{
    private int z;
    public readonly Func<int, int> M = (int x)=>{ return x+z; }
    // ... and so on
}

?

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


4
वाह! यह याद दिलाता है कि मैं क्यों # c से प्यार करता हूँ! मैंने जिन भाषाओं के साथ काम किया है, उनमें कॉम्पैक्टनेस, लचीलापन और पठनीय शब्दार्थ का सही संतुलन है। केवल तुलनीय भाषा ऑब्जेक्ट पास्कल है।
ATL_DEV

1
@ATL_DEV: इसका एक कारण है। C # भाषा के वास्तुकार, एंडर्स हेजलबर्ग, पहले डेल्फी के वास्तुकार थे, जो ऑब्जेक्ट पास्कल पर आधारित एक भाषा थी।
एरिक लिपर्ट

9

यह आंशिक रूप से आवश्यक है क्योंकि यदि आप eventकीवर्ड को छोड़ देते हैं , तो यह एनकैप्सुलेशन को तोड़ देता है। यदि यह सिर्फ एक सार्वजनिक मल्टीकास्ट प्रतिनिधि है, तो कोई भी इसे लागू कर सकता है, इसे इसके साथ अशक्त या छेड़छाड़ कर सकता है। यदि कोई वर्ग MailNotifierमौजूद होता है और उसके पास एक ईवेंट होता है MailReceived, तो यह उस ईवेंट को कॉलिंग के माध्यम से फायर करने में सक्षम होने के लिए कोई अर्थ नहीं रखता है mailNotifier.MailReceived();

दूसरी ओर, आप केवल उस प्रकार की घटनाओं से 'फ़ील्ड की तरह' के साथ ध्यान आकर्षित कर सकते हैं और इसे 'फ़ील्ड' कह सकते हैं।

यदि आप अपने ईवेंट को निजी रखना चाहते हैं, तो आपको ऐसा कुछ करने से रोकना नहीं है:

public class MyClassWithNonFieldLikeEvent
{
   private CustomEventHandler m_delegate;

   public void Subscribe(CustomEventHandler handler) 
   {
      m_delegate += handler;        
   }

   public void Unsubscribe(CustomEventHandler handler)
   {          
      m_delegate -= handler;
   }

   private void DoSomethingThatRaisesEvent()
   {
      m_delegate.Invoke(...);
   }       
}

... लेकिन यह केवल (अधिक या कम) कोड का एक पूरा भार है जो क्षेत्र-जैसी घटनाओं को पहले ही दे देता है।


यह डिजाइनरों के लिए उपयोग की जाने वाली चीजों के लिए भी कठिन होगा ... आप मूल रूप से तरीकों के लिए नामकरण सम्मेलनों पर भरोसा कर रहे होंगे, बजाय इसके कि सार्वजनिक मेटाडाटा कहा जा रहा है "यह एक घटना है"।
जॉन स्कीट

3

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

देखें इस ब्लॉग पोस्ट में अधिक जानकारी के लिए।


2
आपको वास्तव में घटनाओं और प्रतिनिधियों की तुलना नहीं करनी चाहिए - एक प्रतिनिधि प्रकार के साथ घटनाओं और सार्वजनिक क्षेत्रों की तुलना करें । और नहीं, ढांचे को उस हस्ताक्षर के लिए घटनाओं की आवश्यकता नहीं है। आप अपनी पसंद के किसी भी प्रतिनिधि प्रकार की एक घटना बना सकते हैं।
जॉन स्कीट

3

प्रतिनिधि एक संदर्भ प्रकार है। यह मल्टीकास्टडेलगेट को विरासत में मिला है । घटना एक संशोधक है। प्रतिस्पर्धाप्रतिनिधि के लिए एक विशेष संशोधक है। यह कुछ फ़ंक्शन / विधि पहुंच को संशोधित करता है, उदाहरण के लिए इनवोक विधि। संशोधक घटना द्वारा संशोधित होने के बाद, एक प्रतिनिधि उदाहरण एक नई अवधारणा "इवेंट" बन जाता है। इसलिए इवेंट सिर्फ एक संशोधित प्रतिनिधि है। आप सीधे उस कार्यक्रम को नहीं बदल सकते हैं या उस घटना के बाहर एक घटना का आयोजन कर सकते हैं जहाँ घटना को परिभाषित किया गया था, लेकिन आप संदर्भ को बदल सकते हैं या सामान्य प्रतिनिधि उदाहरण को आमंत्रित कर सकते हैं। ईवेंट अतिरिक्त सुरक्षा प्रदान करता है, ताकि ईवेंट में अधिक सुरक्षा सुविधाएँ हों। जब आप उस वर्ग के बाहर होते हैं जहाँ घटना को परिभाषित किया गया था, तो आपके द्वारा इवेंट को दो प्रकार के संचालन करने की अनुमति दी जाती है, "+ =" और "- ="। लेकिन आप एक सामान्य प्रतिनिधि उदाहरण के सभी सार्वजनिक क्षेत्र, संपत्तियों, विधियों आदि का उपयोग कर सकते हैं। यहाँ एक उदाहरण है:

namespace DelegateEvent
{
    //the following line behave as a class. It is indeed a reference type
    public delegate void MyDelegate(string inputs);

    //The following line is illegal. It can only be an instance. so it cannot be directly under namespace
    //public event MyDelegate MyEvent;


    public class MyClassA
    {
        public event MyDelegate MyEventA;
        public MyDelegate MyDelegateA;


        System.Threading.ManualResetEvent MyResetEvent = new System.Threading.ManualResetEvent(false);
        public void TryToDoSomethingOnMyDelegateA()
        {
            if (MyDelegateA != null)
            {
                //User can assecc all the public methods.
                MyDelegateA("I can invoke detegate in classA");         //invoke delegate
                MyDelegateA.Invoke("I can invoke detegate in classA");  //invoke delegate
                IAsyncResult result = MyDelegateA.BeginInvoke("I can invoke detegate in classA", MyAsyncCallback, MyResetEvent);    //Async invoke
                //user can check the public properties and fields of delegate instance
                System.Reflection.MethodInfo delegateAMethodInfo = MyDelegateA.Method;

                MyDelegateA = testMethod;                   //reset reference
                MyDelegateA = new MyDelegate(testMethod);   //reset reference
                MyDelegateA = null;                         //reset reference


                MyDelegateA += testMethod;                  //Add delegate
                MyDelegateA += new MyDelegate(testMethod);  //Add delegate
                MyDelegateA -= testMethod;                  //Remove delegate
                MyDelegateA -= new MyDelegate(testMethod);  //Remove delegate
            }
        }

        public void TryToDoSomethingOnMyEventA()
        {
            if (MyEventA != null)
            {
                MyEventA("I can invoke Event in classA");           //invoke Event
                MyEventA.Invoke("I can invoke Event in classA");    //invoke Event
                IAsyncResult result = MyEventA.BeginInvoke("I can invoke Event in classA", MyAsyncCallback, MyResetEvent);      //Async invoke
                //user can check the public properties and fields of MyEventA
                System.Reflection.MethodInfo delegateAMethodInfo = MyEventA.Method;


                MyEventA = testMethod;                   //reset reference
                MyEventA = new MyDelegate(testMethod);   //reset reference
                MyEventA = null;                         //reset reference


                MyEventA += testMethod;                  //Add delegate
                MyEventA += new MyDelegate(testMethod);  //Add delegate
                MyEventA -= testMethod;                  //Remove delegate
                MyEventA -= new MyDelegate(testMethod);  //Remove delegate
            }
        }

        private void MyAsyncCallback(System.IAsyncResult result)
        {
            //user may do something here
        }
        private void testMethod(string inputs)
        {
            //do something
        }

    }
    public class MyClassB
    {
        public MyClassB()
        {
            classA = new MyClassA();
        }
        public MyClassA classA;
        public string ReturnTheSameString(string inputString)
        {
            return inputString;
        }


        public void TryToDoSomethingOnMyDelegateA()
        {
            if (classA.MyDelegateA != null)
            {
                //The following two lines do the same job --> invoke the delegate instance
                classA.MyDelegateA("I can invoke delegate which defined in class A in ClassB");
                classA.MyDelegateA.Invoke("I can invoke delegate which defined in class A in ClassB");
                //Async invoke is also allowed

                //user can check the public properties and fields of delegate instance
                System.Reflection.MethodInfo delegateAMethodInfo = classA.MyDelegateA.Method;

                classA.MyDelegateA = testMethod;                   //reset reference
                classA.MyDelegateA = new MyDelegate(testMethod);   //reset reference
                classA.MyDelegateA = null;                         //reset reference


                classA.MyDelegateA += testMethod;                  //Add delegate
                classA.MyDelegateA += new MyDelegate(testMethod);  //Add delegate
                classA.MyDelegateA -= testMethod;                  //Remove delegate
                classA.MyDelegateA -= new MyDelegate(testMethod);  //Remove delegate

            }

        }
        public void TryToDoSomeThingMyEventA()
        {
            //check whether classA.MyEventA is null or not is not allowed
            //Invoke classA.MyEventA is not allowed
            //Check properties and fields of classA.MyEventA is not allowed
            //reset classA.MyEventA reference is not allowed

            classA.MyEventA += testMethod;                  //Add delegate
            classA.MyEventA += new MyDelegate(testMethod);  //Add delegate
            classA.MyEventA -= testMethod;                  //Remove delegate
            classA.MyEventA -= new MyDelegate(testMethod);  //Remove delegate
        }

        private void testMethod(string inputs)
        {
            //do something here
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.