DEV Community

Cover image for Underrated concepts in C#: Delegates and Events
Abdul
Abdul

Posted on

Underrated concepts in C#: Delegates and Events

Intro

Hello and welcome to another blog post, about something that I either didn't know or didn't fully understand (and somehow got away with in my career 😆). In this particular post we will be looking into delegates and events, what they are and how they're used.

What are delegates and events?

I've used these two C# keywords in applications before and know what they can do what, why it's used for. But for some reason I can't put it into words, my initial thoughts were that it was because I think I didn't understand it correctly.

Delegates

According to Microsoft A delegate is a type that holds a reference to a method. A delegate is declared with a signature that shows the return type and parameters for the methods it references, and it can hold references only to methods that match its signature.

I agree with this statement fully, but to me it makes more sense to think of it as a type the can hold a reference to a method, as well as be used as a type for declaring an event (this will be explored in the next section). Some also see delegates as a contract between the publisher and the subscriber, in that all the events related to a particular topic will be sent with a particular type.

Example-1

In the example above, we can see a few things happening. Firstly, the declaration of the delegate DoSomething can be seen in line 4. Line 8 shows the assignment of the delegate to a method in line 8. We can also see they're being called in line 9 which produces the Normal text: normal text console output. We can also see it being overridden in line 11 and called again in line 12 to demonstrate the override successfully. This satisfies the statement that delegates can hold references to other methods.

Events

However, what about the other statement I mentioned that delegates can be used as a type when declaring events? Well, we can see it in line 5 where the event named ThresholdReached is being declared. This ties in with the notion of agreement in contract between decoupled classes, essentially saying that any event in this name will be of this delegate type. But, how do we use this event, what does an event really mean in relation to delegates?

Lets go back to Microsoft again, to decipher its definition. It has a few definitions in different areas of it's website, but the simplest one I found was: Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers..

The statement of allowing a class to notify another class of happenings is true, however I could do the same with just an instance of a delegate.

with event keyword

The picture above functions the same as the picture below:

without event keyword

The event keyword technically fits the bill, however the concept of an event doesn't just belong to it on it's own as we can see. On a surface level, it helped me to accept that, for my current understanding, the event keyword is used for clarity and to restrict external classes from assigning = their method to it (thereby wiping out other subscribers) rather than adding to it +=.

So what use is are events and delegates?

One interesting thing about the pictures shared above is that the outputs are displayed in the order that the methods subscribed to the event. This can give us a clue as to how it can be used, we can create a queue of methods that can be called in order.

A benefit of using delegates is that, not all classes need to know of each other to execute together. For example, a class that holds 5 injected services could instead be replaced by a single delegate that allows external classes to subscribe to it's events. this way, the original class does not need to know any external unrelated classes, and the external classes are responsible for their own subscription.

I recently found out that we can execute asynchronous programming using delegates 👀. I haven't looked into it as deep as I'd like to yet, but from what I can see, the BeginInvoke method that is available on delegates allows the main thread to continue execution on the main thread. The original thread, which submitted the request, is free to continue executing in parallel with the target method. This can be useful for time critical operations that require parallel processing like database operations etc.

An easier way of using delegates and events

Microsoft has come up with a way to remove the need to go through the steps of creating a delegate and then defining an event using that delegate signature. It's called `EventHandler, which I had no idea it was introduced donkey years ago:

Versions where it was available

The EventHandler is actually a delegate itself, with a more or less common scenario signature, in that it allows the subscriber of the event to know who sent it (the first argument in the signature - the sender/publisher) and what arguments to expect (the second argument - EventArgs). This is what declaring it looks like as opposed to the initial way mentioned:

Delegate and event equals EventHandler

Mind you, this applies the same things as I mentioned in regards to the event keyword, since it's a delegate as well. So having or not having the keyword would not make much of a difference still.

Event handlers can be genericised as well, to accommodate for any arguments that he sender may want to send to their subscribers. This can be done through inheriting from the simple EventArgs class and adding our own properties to it, more on it here.

Inheriting from EventArgs

This class is then used as a generic type for the event handler, which informs it that the receivers of the message will be expecting an object of certain type with certain properties (i.e expecting the ShoeSize property to be present when handling the event).

Extra notes

I used to see a check for null before invoking the handlers and I never knew why that was done. It turns out that handlers that have no subscribers are essentially null references. This makes sense because when we're declaring these event handlers, more often than not, we don't actually assign it on the spot. We either add subscribers to it or assign a function to it later or (with the = sign). I tested this and tried to invoke a "subscriber-less" event handler and sure enough got a null reference exception.

But what about when we initialise it? Looks like that doesn't have any problems, since it has a subscriber at it inception:

First fan

So we've learnt about delegates, events and event handlers, how to use them, when to use them and some small general notes on it. I hope you've learnt something as I did. If I made any mistakes please let me know I would love to keep track of it and make changes so I do not lead people astray. Let's keep learning and falling in love with our craft, much love! 🙌

Top comments (0)