Delegates and Events in C#

Eslam Ali
C# Programming
Published in
5 min readMay 25, 2021

this is a rep for the projects that illustrates the examples here GitHub.

Today's software is not simple anymore it must be Reliable, Scalable, and Maintainable. And no matter what you are building a Monolithic application or microservices software which is the best for embracing these concepts by making independent services that communicate via much reliable communication ensuring that communication will happen sooner or later even if other services are down. but we will discuss that in later articles after discussing more concepts that will build this knowledge and crafting this amazing skill of designing good software. but before all this, you should know the first one the primary skills: Events and Delegates.

So first of all what is an Event?

We can look at the simple button click. or we could go to a drop-down list and handle the selected index changed event, or where you might even have a custom object like an order object that when a customer places an order an event notification might go out and notify other parts of the system that hey, an order has been placed, and sending this custom object as arguments to all the other parts. And then they can act upon that to start the shipping and start the billing and all of those types of actions.

Great!.

ok, but you might ask yourself who is responsible for notifies and transferring all this information as arguments to whoever is subscribing to these events?

Congrats, you guessed it right. It's the Delegate.

In fact, without delegates, data wouldn't be transmitted from the publisher to all the subscribers. so delegate actually is the pipeline between the event and the event handlers.

so how does that delegate do that? how does it knows which functions or methods are responsible for handling events? does they all run at the same time or in sequence? And how does it transfer that data?

Delegates are just contracts that are telling you which method signature and return type is used for data to be transferred or for subscribers to subscribe for an event.

So this example here is a delegate.

public delegate void WorkPerformedHandler (int hours);

Delegates are declared outside classes, and they inherit from the Delegate or the MulticastDelegate Class (used with events ) and they are sealed classes so you are not allowed to inherit from them. but behind the scene, the compiler will generate a class for that delegate and will inherit from them and the compiler only is allowed to that, so do not try to inherit from them by yourself.

and this is how to write methods for this delegate.

static void WorkPerformed1(int hours)
{
Console.WriteLine($"Work performed is {hours} Hours in method WorkPerformed 1");
}

static void WorkPerformed2(int hours)
{
Console.WriteLine($"Work performed is {hours} Hours in method WorkPerformed 2");
}

static void WorkPerformed3(int hours)
{
Console.WriteLine($"Work performed is {hours} Hours in method WorkPerformed 3");
}

So all methods should be void which does not return anything and should take the same parameter.

So now we want to make a handler to assign functions to execute. and here is how to make a handler

WorkPerformedHandler handler = WorkPerformed1;

a handler handles the methods that will be executed. yes, methods not just one method.

and this is how to execute a handler

handler(5);

which will call the "WorkPerformed1" function. and will output this.

Work performed is 5 Hours in method WorkPerformed 1

We could actually add more methods for the handler to execute. and adding a method to it is very easy just like that.

handler += WorkPerformed2; 
// calling handler(5) will outs puts
//Work performed is 5 Hours in method WorkPerformed 1
//Work performed is 5 Hours in method WorkPerformed 2

// or you may add more like that handler += WorkPerformed2+ WorkPerformed3;

what happened behind the scene is that handler has a list called an invocation list. and invocation list is an ordered list of functions that will be called one by one when this handler is called. So now actually what will happen is it will call the "WorkPerformed1" then "WorkPerformed2" function. and you can add a function as many times as you want and it is simply invoked once per occurrence.

and also you can add a handler to another handler and it will add its invocation list to the handler it's assigned to.

So how to write an event and raise it?

Events syntax look like this

public event WorkPerformedHandler WorkPerformed;
// then assign a method to handle the event fired
WorkPerformed += WorkPerformed1;

And event raised by calling it like a method, because what's actually behind and event? It's a delegate. But before you call it you must assign methods to handle the event first. and a good tip here to check for null before raising the event.

if(WorkPerformed!=null){
WorkPerformed(5)
}
// OR an easier way to use null conditional operator
WorkPerformed?.Invoke(5);
// and that will just call one method and ofc you can add more to it.

So now let's go on and define a new event but this time based on the EventHandler Class.

public event EventHandler WorkCompleted;

And that Event handler requires the handler to accept two arguments. it takes an object and EventArgs. so behind the scene, it's just a delegate looks like that

public delegate void EventHandler(object? sender, EventArgs e);

So how do we send a custom EventArgs? by calling EventHandler<TEventArgs>

//the WorkPerformedEventArgs class contains one int property for hours
//public int Hours { get; set; }

public event EventHandler<WorkPerformedEventArgs> WorkCompleted;

// and behind the scene it looks like this

public delegate void EventHandler<WorkPerformedEventArgs>(object? sender, WorkPerformedEventArgse);

And any method that handles that event must be the same signature and it looks like this.

private static void Workcompleted(object? sender, WorkPerformedEventArgs e)
{
Console.WriteLine($"workcompleted and the number of hours is {e.Hours}");

}

// now we assign it to the event
WorkCompleted += Workcompleted;
//then raise then event
WorkCompleted?.Invoke(this, new WorkPerformedEventArgs {Hours = 5});

just as easy as that.

and final piece of data here is the return type of the delegate, If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.

In the next articles, I will demonstrate how to use Events properly to make loosely coupled applications. And how to make a mediator class that handles the events so that the subscriber and the published wouldn't be wired together and that will make the application more maintainable.

And after that, I will demonstrate how to use asynchronous programming with events and delegates to make more reliable, fast, and responsive applications.

I hope you like this guide and understood the idea of Events and Delegates.

You can download the project from GitHub. it's a little bit different than the code here but you will get the Idea. And please lets me know about any questions you have about this subject or another. And can suggest to me new subjects for me to demonstrate.

Goodbye.

--

--