Why do we need the “event” keyword while defining events?

后端 未结 6 1686
忘了有多久
忘了有多久 2020-11-29 17:43

I don\'t understand why do we need the \"event\" keyword while defining events, when we can do the same thing without using \"event\" keyword, just by using the delegates.

相关标签:
6条回答
  • 2020-11-29 18:12

    The other answers are fine; I'd just like to add something else to think about.

    Your question is "why do we need events when we have fields of delegate type?" I would extend that question: why do you need methods, properties, events, instance constructors or finalizers if you have fields of delegate type? Why do you need anything other than fields that contain values and delegates in a type? Why not just say

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

    ?

    You don't need methods, properties or events. We give you that stuff because the method, property and event design patterns are important and useful, and deserve to have a standard, documented, clear way to implement them in the language.

    0 讨论(0)
  • 2020-11-29 18:19

    Events have distinct advantages compared to delegate-fields. Events can be defined in interfaces in contrast to fields, adding abstraction to the code, and even more importantly: Events can only be called from inside the defining class. In your case, anybody could call the event, possibly destroying your code.

    See this blog post for further information.

    0 讨论(0)
  • 2020-11-29 18:26

    Field-like events and public fields of delegate types look similar, but are actually very different.

    An event is fundamentally like a property - it's a pair of add/remove methods (instead of the get/set of a property). When you declare a field-like event (i.e. one where you don't specify the add/remove bits yourself) a public event is created, and a private backing field. This lets you raise the event privately, but allow public subscription. With a public delegate field, anyone can remove other people's event handlers, raise the event themselves, etc - it's an encapsulation disaster.

    For more on events (and delegates) read my article on this topic. (At some point I need to update this for C# 4, which changes field-like events very slightly. The gist of it is still correct though.)

    0 讨论(0)
  • 2020-11-29 18:30

    delegate is a reference type. It inherit MulticastDelegate. event is a Modifier. event is a special modifier for delegate. It modifies some function/method accessibility, for example Invoke method. After modified by modifier event, a delegate instance become an new concept "Event". So Event is just one modified delegate. You cannot directly change reference or invoke an Event outside the class where the Event was defined, but you can change reference or invoke a normal delegate instance. Event provide additional protection, so that Event have more safety features. When you are outside the class where the event was defined, your are allow to do two kind of operations to the Event, "+=" and "-=". But you can do access all the public field, properties, methods etc. of a normal delegate instance. Here is one example:

    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
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 18:32

    It's partly needed because if you omit the event keyword, it breaks encapsulation. If it's just a public multicast delegate, anyone can invoke it, set it to null or tamper with it. If a class called MailNotifier exists and it has an event called MailReceived, it makes no sense for other types to be able to fire that event via calling mailNotifier.MailReceived();

    On the other hand, you can only meddle with and invoke 'field like' events from the type that defined it.

    If you wanted to keep your event invocation private, there's nothing to stop you doing something like this:

    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(...);
       }       
    }
    

    ... but that's a whole load of code just to (more or less) do what field-like events already give us.

    0 讨论(0)
  • 2020-11-29 18:36

    The event keyword does 3 different things:

    1. You can define an event in an interface, even though you cannot define regular fields in interfaces.
    2. It changes the visibility of the = and () operators (assignment and invocation) to private, so that only the containing class can invoke the event or override all the methods contained in it. The -= and += operators can still be invoked on an event from outside the class defining it (they get the access modifier you wrote next to the event).
    3. You can also override the way -= and += behave on events.
    0 讨论(0)
提交回复
热议问题