Delegates

This post is about an extremely seasoned topic from C#, which many new programmers face difficulty understanding – Delegates and Events.

I have noticed, even a C# programmers with over 5 years of experience become a bit nervous when they are asked to explain delegates in the interviews and sometimes even go on the back-foot saying they have used it very little. On the other hand, the idea of delegates and functional programming is so prevalent in C# that any programmer have hardly gotten away from using it.

So, in this post I am going to go through the basics of C# delegates and events such that they no longer feel confusing and complex.

Imagine you require a variable to reference a method. A variable that encapsulates executable lines of code and can be invoked like a method. A delegate is nothing but a way to provide this functionality in C#.

Delegate is a user defined type (just like a class or a struct) that can hold a reference to certain method. Simple enough?

The only condition is that, the delegate declaration should match the signature of method it can hold reference to. i.e. the input parameters it take and the type of value it can return.

So let’s take a look at declaring a delegate. Suppose we want to create a delegate that can hold a reference to method taking two string inputs and returns a void.

The code above declares delegate type NameChangedDelegate which can hold any number of methods that take two string arguments and returns void. This is analogous to declaring a class. Note that here, the name of arguments in the delegate declaration do not matter and need not match with actual methods that are held by this delegate.

Now that we have declared a delegate let’s now create an instance of the same (much like how we instantiate a class) wherever we want to use this delegate.

Note that the method OnNameChanged is added to the delegate at the time of initialization which can be invoked anonymously using the delegate instance. The signature of the delegate has to match with the signature specified in delegate type.

This is all the wiring we need. Now, whenever we want to call the method OnNameChanged we simply need to invoke the delegate as below

The real use case for delegate becomes clear when we dig into what is called a multicast delegate

A multicast delegate is the one, to which more than one methods can be added. The condition is that all methods should abide by the method signature as specified by delegate. Using delegate instance all these methods can be invoked anonymously.

So in order to add more than one method to a delegate we can use += operator.

In the code above, the NameChanged delegate holds, actually holds a reference to four methods three methods added using += operator above and the one added when instantiating a delegate type.

Similarly, in order remove reference of a method from a delegate we can use -= operator.

NameChanged -= OnCountryNameChanged

Now, here is a problem with multicast delegate, suppose somewhere in the class DelegateUser, someone mistakenly re-instantiates a delegate as below:

NameChanged = new NameChangedDelegate(OnTownNameChanged);

This will basically, wipe out all previous method references that delegate was holding on to! So, the calling the delegate instance to invoke underlying methods, will only invoke one method OnTownNameChanged

NameChanged("SomeOldName", "SomeNewName");
//Expected output:
The name has been changed from SomeOldName to SomeNewName
The city has been changed from SomeOldName to SomeNewName
The state has been changed from SomeOldName to SomeNewName
The town has been changed from SomeOldName to SomeNewName
// Actual output
The town has been changed from SomeOldName to SomeNewName

In order to avoid this issue, C# introduces a keyword event. An event is a type of multicast delegate that can only be subscribed to or unsubscribed from, but cannot be instantiated on its own.

By decorating the instance of NameChangeDelegate by a keyword event, we are essentially preventing it from getting initialized. In this case, the event OnNameChanged can only be subscribed to or unsubscribed from using += and -= operators.

However, the convention in .NET says, an event does not take arbitrary arguments like two strings, instead it takes two arguments – a System.object type sender and EventArgs type that encapsulates the arguments sent to it.

They provide a way to hold reference to a method, and can be invoked like a method

The signature of delegate declaration must match the signature of method it is supposed to hold reference to

A multicast delegate is the one that can hold reference to more than one methods

Delegates are foundation of event driven programming and functional programming in C#

Event

Event is a type of multicast delegate to which method can be added and removed, or subscribed to and unsubscribed from

Event cannot be directly instantiated using new keyword

To subscribe to and event use C# operator +=

To unscubscribe from an event use C# keyword -=

By convention an event signature takes two parameters, a type of System.object which is the sender, and a type derived from EventArgs which contains additional parameters to be sent to the event

Toy Exercise:

Simulate the working of train, with and engine and wagons where, wagons are attached to engine and main controls are in engine. i.e. when engine starts all attached wagon get started and when engine breaks all attached wagons break

Hope this post makes some of fundamentals around delegate and event driven programming clearer. Let me know if I have missed out anything.

Also, I would like to mention the reference to this article is from plural-sight course by K. Scott Allen on C# fundamentals with C# 5 The basic understanding is built upon the concepts explained in there. I have tried to elaborate it through an example