5

I've been confused over the past weeks now about events. I understand how delegates work, not how it works in detail but enough to know that delegate datatype is a single cast delegate. delegate void is a multicast delegate - a list of references to methods.

I know a delegate type compiles to a class, but unfortunately I am still not sure how the method is referenced. For example

delegate void TestDelegate();
TestDelegate testDelegate = new TestDelegate(myObject.SomeMethod) ;

Question 1: I think myObject is the target, and SomeMethod is the method to reference, but I'm only passing one input. So is myObject.SomeMethod compiled to a string and is the string split by the period? Ridiculous I know.

Question 2: When you add to a multicast delegate

multicastdelegate+=newmethodtobereference
multicastdelegate() ;

Every method in the invocation list is called or notified? If that's true, why the hell do I need events or the event keyword? Is it simply to tell the developers that Hey, this is acting as an event? Because I'm seriously confused, I just want to move on at this stage lol. This is a sample code I wrote to test it today whether I need event keyword or not.

using System;
namespace LambdasETs
{
    public delegate void IsEvenNumberEventHandler(int numberThatIsEven);

    public class IsEvenNumberFound
    {
        public  IsEvenNumberEventHandler IsEvenNumberEvent;
        private int number;

        public void InputNumber(int n)
        {
            if(number %2 ==0)
            {
                if (IsEvenNumberEvent != null)
                {
                    IsEvenNumberEvent(n);
                }
            }
        }


        public static void Main()
        {
            IsEvenNumberFound isEvenNumberFound = new IsEvenNumberFound();

            isEvenNumberFound.IsEvenNumberEvent += IsEvenNumberAction;

             isEvenNumberFound.InputNumber(10);

            Console.ReadLine();

        }

        public static void IsEvenNumberAction(int number)
        {
            Console.WriteLine("{0} is an even number!", number);
        }
    }


}

Adding the event keyword to the field public IsEvenNumberEventHandler IsEvenNumberEvent; has no difference. Please can some explain so that a noob can understand thanks.

Lews Therin
  • 10,907
  • 4
  • 48
  • 72

2 Answers2

6

An event is an accessor for a delegate, just like a property is an accessor for a field. With much the same goals, it prevents other code from messing with the delegate object. Like setting it null when a bunch of code you don't know about have subscribed a callback. An event restricts access to only adding and removing event handlers with the += and -= operators, external code cannot access the private delegate object at all.

And to customize the subscription with the add and remove accessors. You don't often do so because you are typically happy with the default accessors generated by the compiler. Including a hidden backing field that stores a delegate. But it is not uncommon in the framework code for example. Like all the event handlers for the many events that System.Windows.Forms.Control supports, they are all stored in a single EventHandlerList. Or the WPF equivalent, EventHandlersStore.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • If that's true why is my compiler complaining about inconsistent inaccessibility? Properties accessibility aren't dependent on the field they reference, but it seems events are.. weird – Lews Therin May 27 '12 at 16:49
  • @LewsTherin: Property accessibility needs to be consistent with the type of the property. Same with events. And fields. – Ben Voigt May 27 '12 at 16:50
  • @BenVoigt I think I see what you mean. If a string is private then a property that returns a string needs to be private as well? Well if it has to be public as the event must be.. what does HansPassant mean by "it prevents other code from messing with the delegate object" I thought that meant changing the signature of the delegate.. apparently not. – Lews Therin May 27 '12 at 16:55
  • @Lews: The type `System.String` is public, so you can have public properties with that type. But make your own class type, `MyInternalType`, and you can have private and internal fields, internal properties, etc., but not a public field or property with that type. – Ben Voigt May 27 '12 at 16:56
  • @BenVoigt So what's the field that the event represents in this case? – Lews Therin May 27 '12 at 17:21
3

but enough to know that delegate datatype is a single cast delegate. delegate void is a multicast delegate - a list of references to methods.

Not true. All "normal" delegates are multicast, even if they have a non void return type.

Question 1: I think myObject is the target, and SomeMethod is the method to reference, but I'm only passing one input. So is myObject.SomeMethod compiled to a string and is the string split by the period? Ridiculous I know.

No, myObject.SomeMethod is a method group. This way of delegate instance creation involves a bit of compiler magic.

multicastdelegate+=newmethodtobereference

If multicastdelegate is a normal delegate variable, this is equivalent to multicastdelegate = multicastdelegate + newmethodtobereference i.e. it creates a new delegate that calls several methods, and assigns it to multicastdelegate.


Now to your main question: What's the purpose of events?

Events have delegate types. They behave similarly to properties. Their purpose is encapsulation, in particular they only allow consumers to subscribe(+=) and unsubscribe(-=) but not to read the value of the event.

Properties are a combination of two methods: get and set.

Events are a combination of two public methods subscribe and unsubscribe, and in the case of a field-like event also something similar to a private getter.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • Sorry, but what is a method group in `myObject.SomeMethod` "it creates a new delegate that calls several methods" I never thought about it like that. Imagine, is it like a delegate is a pointer to a list of other delegates which can act as a pointer to a list of other delegates.. my God, how convoluted. – Lews Therin May 27 '12 at 16:52
  • Delegates are immutable. I think internally there are optimizations for single cast delegates, and an array for multi cast delegates, but all delegate types derive from `MultiCastDelegate`. – CodesInChaos May 27 '12 at 17:02