Monday, October 06, 2008

Delegate vs. Event

What's the difference between a delegate and an event in C#, you ask? An event provides better encapsulation (read: a more object orientated approach) while a delegate is "merely" a immutable multicast type-safe function pointer. In other words, an event is an encapsulated delegate, where only the += and -= functions are non-private. That means that although we can add new subscribers to the event from another class, we cannot invoke it. The add and remove accessors are the only members to retain the event's declared access (e.g. public).

It's easier to explain delegates first.

Delegates


  • Function pointer: a delegate acts as a layer of indirection allowing references to methods to be passed between objects. The target methods are invoked when the delegate is invoked.
  • Type-safe: unlike function pointers in C++, a delegate knows the type of the target object, and the signature of the target method.
  • Multicast: a delegate maintains a list of methods; it isn't limited to invoking just one
  • Immutable: delegate instances - like strings - cannot be changed. When you add/remove another target method to/from a delegate instance, you're really creating a completely new delegate instance with a superset/subset of target methods.

    A delegate example


    Define the delegate type, or use one of the many predefined types shipped with the FCL.
    public delegate void Function(string value);
    Define the target methods that we can call. These will have to conform to the signature of the chosen delegate type.

    static void WriteOut(string value)
    {
    Console.Out.WriteLine(value);
    }

    static void WriteError(object value)
    {
    Console.Error.WriteLine(value);
    }

    Define a class with a public delegate field (bad object-oriented encapsulation, but it's just for the purpose of example).

    class DF
    {
    public Function function;
    }

    Construct a new instance of this class, add a couple of target methods and invoke them through the delegate:

    DF df = new DF();
    df.function += new Function(WriteOut);
    df.function += new Function(WriteError);
    df.function("Delegate");


    Events


    An event is a construct that is functionally similar to a delegate, but provides more encapsulation. Specifically, adding/removing target methods is given the accessibility of the event (e.g. public/protected/internal). Everything else is given the accessibility modifier of "private". This allows subscribers to be notified of an event, but not to trigger it themselves.

    An event example


    Again, pick a delegate type from the FCL or define your own. For this example, I will reuse the Function delegate type, and the two Function methods defined above.
    Define a class with an Event:

    class EF
    {
    public event Function function;
    }

    Construct a new instance of this class, add a couple of target methods:

    EF ef = new EF();
    ef.function += new Function(WriteOut);
    ef.function += new Function(WriteError);

    Because of the encapsulation, we cannot call the following method from outside the declaring type:

    //ef.function("Event"); // ... can only appear on the left hand side of += or -= (unless used from within the event's declaring type)


    A good technical resource:
    Difference between a delegate and an event.
  • No comments: