Simple explanation to Delegates and Events

Recently, several colleagues at work asked me these 2 questions. “What exactly is a delegate?” and “What’s the difference between an event and a delegate?“.

If you know the answer to both of these, read no further. For the rest of us, let’s see if we can make it easier to understand. We’ll start with the delegate.

The Delegate

Here’s MSDN’s definition:

confusedA delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

Great, now we understand delegates, let’s move on to events! Just kidding…

If you’re anything like I was when I was studying, you probably would have read this definition 10 times, know it well for an exam, but practically you’re still clueless about what a delegate truly is. So here’s my little definition:

This is a container (delegate)container

triangleThis is a shaped block (method / piece of work)

So my definition is that a delegate is:

  • A container (delegate)
  • It can hold shapes (methods or pieces of work)
  • It may only take shapes which fit through the holes in the lid (same signature)
  • The container can hold one or many methods or pieces of work (multicast delegates)

So basically the concept is, that you put all your pieces of work into a container and can now pass it around.

Let’s see some code… Objective: Pass your awesome method as a parameter.


public string MyMethod()
{
  return "Hello World";
}

// This code doesn't compile...
public void ReceivingMethod(MyMethod() method)
{
}

After the above attempt, It doesn’t seem possible to pass a method as a parameter?!? Sure would be nice though…

But we are allowed to pass a container (delegate) to another method.

We will create a container (delegate) and we will put the block (my method) into the container. Then we’ll pass the container to the ReceivingMethod in line 7. Also remember to make the holes of the container (signature) the right shape for the block (method) to fit. Here’s 4 easy steps to do that:

Step 1: Figure out how the container (delegate) lid (signature) should look.

Let’s inspect our block (method) so we know what the container’s (delegate) lid (signature) should look like.

methodsignature

This is what our lid must look like: string return type and no parameters

Step 2: Create the container (delegate)

The code line below is a container (delegate) with the correct a lid (signature) that matches our block (method)

public delegate string MyContainer();

Step 3: Add the container (delegate) as a parameter

See that the parameter is MyContainer which is the container (delegate) we created in step 2.

public void ReceivingMethod(MyContainer container)
{
}

Step 4: Now we can pass our method as a parameter

Finally we put our block (MyMethod) into our container and pass it to ReceivingMethod

MyContainer container = MyMethod;
// container += AnotherMethod; // - This would add another block to the container.
ReceivingMethod(container);

Line 2 above, shows how we would add more blocks (methods) into the container (delegate) if we wanted to. In this case we only wanted to pass 1, so it would be easier to pass the method directly, as follows:

ReceivingMethod(MyMethod);

Now that we know how to pass method(s) around, how do we use the blocks in container? (i.e how do we invoke all methods, stored in the delegate)? Good question. Here we see just how easy it is to do that. Just as if we were calling any other method:

class Program
{
  public static void GreetWorld()
  {
    Console.WriteLine("Hello World");
  }

  public static void MakeSomeCoffee()
  {
    Console.WriteLine("Making Coffee...");
  }

  static void Main(string[] args)
  {
    MyContainer container = GreetWorld; // Add 1st block to container
    container += MakeSomeCoffee; // Add 2nd block to container
    ReceivingMethod(container); // Pass container to method

    Console.Read();
  }

  public delegate void MyContainer();
  public static void ReceivingMethod(MyContainer container)
  {
    Console.WriteLine("Executing all blocks in container...");
    container(); // Use each block in container
    Console.WriteLine("Done with all blocks");
  }
}

The above code puts 2 methods into a delegate, passes the delegate to another method, which then invokes all methods in the delegate. Line 26 Invokes the methods stored in the delegate. Here’s the result:

screenshot5

The highlighted 2 lines are from the blocks (methods) in the container (delegate). When we invoke a delegate, we execute all methods that are stored in the delegate.

The way to declare a delegate has changed quite a lot as the .NET framework progressed. We see many different forms of it, such as Action, Func, () => … (lambda) etc. Have a look at the evolution of the delegate article to see and understand the different forms of the delegate and how we ended up with the lambda function.

The Event

Hopefully by this point, you’ve a few “Ah, I get it!” moments and delegates are less intimidating. To truly understand events, we need a solid understand of delegates. If you’re still unsure about delegates at this point, I’m afraid my article has let you down and I’d advise you to do some more research on delegates first.

You may have noticed that when we add multiple blocks (methods) to the container (delegate), we used “+=” I’m sure most of you would also be familiar with the += to assign a method to an event. Example:

this.btnSave.Click += btnSave_Click;

So what makes an event so different from a delegate? The answer is Security

securitylock

Not what you expected? Well let’s put it like this…

Think of an event as the Lock, rather than the bouncer. An event is the lock that closes the lid on the container (delegate). With a delegate you can put many blocks into the container, but at any time you could open up the lid, pour out all blocks and put your own block in there. An event is a layer or protection (the lock) which doesn’t allow you to simply throw away all the blocks.

Consider the following. We have a class A which defines an event called myEvent and a delegate myDelegate. Now in class we will be assigning to the event and delegate.

Here in class B, we add 4 methods to the event and 4 methods to the delegate:

// delegate
myDelegate += method1;
myDelegate += method2;
myDelegate += method3;
myDelegate += method4;

// event
myEvent += method1;
myEvent += method2;
myEvent += method3;
myEvent += method4;

So far they’re the same. Now let’s say we want to explicitly remove method3:

// delegate
myDelegate -= method3;

// event
myEvent -= method3;

Still the same. Now both the event and delegate hold methods: 1, 2 & 4.
Here comes the difference. Let’s say we wanted to add method5 and we tried the following:

// delegate
myDelegate = method5; // throws all out and only keeps method5

// event 
myEvent = method5; // compiler error

Notice that we said “=” and not “+=”. The delegate would now only hold method5, whilst the event would not compile.

Also if we tried to set the delegate and event to null, the delegate would work, but the event would fail.

// delegate
myDelegate = null; // throws out all methods

// event 
myEvent = null; // compiler error

That’s the main difference! The event protected the calling code from simply throwing out all methods that would be called when an event occurs.

Logically the way we consider events and delegates are quite different. We tend to see or use delegates more as a type of “template” or “placeholder” or as we mentioned before “container”. As for events we use them to keep all the method(s) which we want invoked when an event something specific happens.

I hope this article has helped to gain some understanding of what delegates and events are as well as the differences between them.

Advertisements

One thought on “Simple explanation to Delegates and Events

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s