C#

C# Delegates – a fairy tale about when (and how) to use them.

Many people neglect C# delegates because they cannot find a reason to use them. On the other hand, there is (rather small) group of people who overuse delegates in code that could be easily replaced by literal method call. So when should we use delegates? Well, they show their real power in situations when we need a mechanism to easily switch from one logic to another, without changing our application’s core code.

Sounds ok but what does it mean in a real life? It’s time for a fairy tale ?. Imagine you are developing a very important application with crucial warning system. For example, our app should inform users about a nuclear reactor temperature rise ?. Our team, developing the reactor’s system, doesn’t know how we will inform workers that temperature is too high. You know, it depends on the business managers and they didn’t decided on it yet, it happens ?. Of course, it doesn’t mean we can make a system without a way to inform workers that something is wrong… The deadline is close, the nuclear reactor will start working tomorrow, the idea of changing your code when the reactor is running makes you feel slightly uncomfortable… There must be another way!

Delegates to the rescue!

That’s it! This little bro will save you from the necessity of rebuilding your code. You can send your project as .dll and everybody who will use it, can apply its own warning logic. Awesome, isn’t it? Let’s have a look at the source code…
First of all, we create a delegate:

public delegate void NuclearReactorWarningHandler(string msg, int currentTemp);

I will just stop here for a moment and add some basic facts.
Delegate is a construction that:

  • Starts with the key word ‘delegate’ (just after public/private/etc key word)
  • Cannot be static
  • Can be defined inside of a class or in the global scope
  • The ‘Handler’ suffix is advisable but not required (it’s just a convention)
  • Can point to both static and non-static methods

In practice, delegate is just a recipe for a method we will use. It doesn’t influence the method’s logic, but limits the returning type and parameters list.

Ok, we have a delegate but what know, how can we use it, if we don’t know the logic of the warning system so we don’t know how it should look like…
Nothing difficult here! We can pass out delegate to a method, as a parameter. Just look at the code:

public void CheckReactorTemperature(int temp, NuclearReactorWarningHandler dlg)
{
   if (temp > 100)
   {
      ApplyCoolingPolicy();
      dlg("Ractor is getting too hot!", temp);
   }
   else
   {
      Console.WriteLine("No worry! Temperature is still OK!");
   }
   //Do other operations.
}

The above CheckReactorTemperature() method takes a delegate as a second parameter. And in the place marked with comment ”(1)”, it calls the delegate method. As simple as that. Notice that in the above code we still don’t know how the warning system will actually work like. But we know where it should be called! So, we can call there our delegate and be sure that somebody’s else logic will work in this line.

Then we hook appropriate methods to the delegate!

Coming back to our fairy tale – a few days passed by, our business managers finally got to the conclusion how the warning system should look like. So, if the reactor temperature is too high on week days, the system should send an email to every worker. Buuuut, on weekends, it should only text employers (because these lazy guys don’t check their emails on Sundays!).

Project managers come to us with a demand to modify our code and what we say? ‘Ha! Too late, everything is done!‘. They congratulate us and offer a pay rise and we, with a blushed face say: ‘Oh, stop it, it was nothing! Everybody in our shoes would do the same!’.
And the fact is that reactor’s system is ready. But we still have to pass the warning system logic to it. How do we do it? By passing a warning method as a parameter to our CheckReactorTemperature(), of course. It’s as simply as that:

static void Main(string[] args)
{
   var wSystem = new ReactorSensorsSystem();	//(1)
   var isWeekend = DateTime.Now.DayOfWeek == DayOfWeek.Saturday || DateTime.Now.DayOfWeek == DayOfWeek.Sunday;
   while(true) //(3)
   {
      Thread.Sleep(1000); //(3)
      int temp = ReactorSensorsSystem.GetTempFromSensor(); //(3)
      if (isWeekend)
      {
         wSystem.CheckReactorTemperature(temp, (new Program()).SendWarningSMS); //(4)
      }
      else
      {
         wSystem.CheckReactorTemperature(temp, SendWarningEmail); //(5)
      }
   }
}

If you are scratching your head, wondering ‘what the heck the above code does?’, let me explain it to you.
(1) – we create an instance of our reactor sensors’ system class.
(2) – we check if current date is on weekend, because on weekend we should text workers
(3) – in an infinite loop, every single second, we ask sensors about the current temperature
(4) – if today date is weekend date, we pass our method “SendWarningSMS” to the reactor sensors’ system method CheckReactorTemperature(). Note, that this method is not static, so it requires an instance of a “Program” object (so we create one first).
(5) – on a week day, we pass our method “SendWarningEmail” to the reactor sensors’ system method CheckReactorTemperature(). Note, that this method is static, so there is no need to create an instance of any class.

The result of our application is visible below.

The whole code you can find on github.

 

But… Are there a real life (real for real!) scenario for using delegates

Of course, there is plenty of them! I just cannot remember any at this moment!
.
.
.
Just kidding, here is a bunch of ideas for a delegate usage:

  • Custom errorlog system – we create a library that collects all the exceptions. The system has a delegate that is called every time a new exception is logged. Thanks to that, a person using our library can store this log in his/her own way (by hooking a custom method to a delegate)
  • Reading data from sensors – again, we create a library that collects all the data from sensors and allow other programmers hook to our delegates
  • Any system that should be scalable and easy to extend (ex. trade commission calculator, but the algorithm can evolve)
  • Any system which requirements are still unclear (but developing such systems is crazy, anyway).

 

Share this: