Delegates to the Event
By Peter A. Bromberg, Ph.D.
Printer - Friendly Version

Peter Bromberg

Like many .NET platform developers who originally migrated from other tools and languages such as classic Visual Basic, much of what I've learned has been self-taught. And the interesting thing about being self-taught, of course, is that often our learning process can be very "selective". That is to say, we learn what we want to learn, not necessarily what we should learn, and very often we "learn it to ourselves" in the wrong order. Sound familiar? I thought it would!



One of the last things I learned was the delegate and event infrastructure that's built into the .NET languages. I avoided getting them under my belt for mostly the above reasons. However, now that I've journeyed through the Valley of Delegate Darkness and emerged at the other side unscathed, I have seen that "it is good". For reasons of clarity, I'm focusing here on C# specifically (also because it's my favorite .NET Platform language, by a long shot).

So, what's a delegate? You'll find a number of definitions, but they all seem to converge around "it's a type-safe, object oriented way to point to a method". In .NET, you can make a call on any method, either synchronously or asynchronously, by simply defining a delegate for the method and invoking the delegate.

First, let's take a look at a delegate "under the hood". Once you understand what the Common Language Runtime is doing with your delegates, you will have a lot more insight into what they can do. I've created a simple class, "DaddysCar" that looks like so:

using System;
namespace Daddy
{ 
 public class DaddysCar
 {
  public DaddysCar()
  {
  }
   private decimal _damageAmount;
  public decimal DamageAmount
  {
   get{ return _damageAmount;}
   set{_damageAmount=value;}
  }
  
  private string _whichCar;
  public string WhichCar
  {
   get{return _whichCar;}
   set{_whichCar=value;}
  }
  public delegate string NotifyDaddy(DaddysCar car, decimal DamageAmount);
 }
}

Note the delegate "NotifyDaddy" defined at the bottom of the class above (I hope you are never the recipient of this method call). Now when we run this through our trusty ILDASM and look inside, see what the Compiler has done for us:

First, we can see that NotifyDaddy, our delegate, is actually a class, and that the compiler has created it as a nested class, since we defined it inside our DaddyCar class (we could have defined it in a separate class too). Note also that the compiler has generously supplied us with both synchronous "Invoke" and asynchronous "BeginInvoke / EndInvoke" methods! Note also that the compiler has derived this class from System.MulticastDelegate. Some of the inherited members we get from this trick are Method (name of the method it points to), Target (name of the class if the method it points to is a member of a class), Combine (a static method to allow our delegate to point to more than one method), and GetInvocationList, which returns an array of each of the Delegate types in the list of methods pointed to. We also get, of course, Clone, the += and -= operator overloads, DynamicInvoke, MethodInfo, and other methods.

So here we've defined a Delegate called NotifyDaddy, and we have indicated that each instance of it can hold details of a method that takes a DaddysCar instance and a decimal damageAmount, and will return a string. I've now added a new method to my DaddysCar class that can act as a sample target of a delegate:

public string ComputePunishment( DaddysCar car, decimal damageAmount)
 {
  if((int)damageAmount >1000.00 && car.WhichCar =="TBird")
   {
     return "Confiscate Car Keys Immediately; Call Insurance Company!";
   }
    else
   {
    return "Look Mad and Issue Stern Warning";
  }

Invoking Delegates

We invoke a delegate by supplying the name of a delegate instance, followed by parentheses containing a list of acceptable parameters. This has the same effect as calling the method pointed to by the delegate. So now let's put together a "Tester" class to flesh this all out:

using System;
using Daddy;
namespace DaddyTester
{
 class TestMeOutDelegate
 {
  delegate string NotifyDaddy(DaddysCar car, decimal damageAmount);
  [STAThread]
  static void Main(string[] args)
  {
   Daddy.DaddysCar d=new DaddysCar();
   d.WhichCar="TBird";
   NotifyDaddy BadNews = new NotifyDaddy(d.ComputePunishment);
   Console.WriteLine("Method: " + BadNews.Method);
   Console.WriteLine("Target: " + BadNews.Target);
   Console.WriteLine(BadNews(d,1500));
   Console.ReadLine();  
  }
 }
}

And here is the output from our delegate call:

The above comprises the very basic, "get to First Base" understanding of delegates. Hopefully it will encourage you to move forward on your own and study more on the use of delegates. Delegates can be used in ASP.NET, with SMTP, Web Services, even in FTP and on applications written for hand held devices such as the PocketPC.

Finally, delegates can be used to call methods asynchronously. For a complete example of how to implement this technique, please visit my previous articles "How to send emails asynchronously".

Now that we have a "basics" example of what a delegate is and how they are used, we can move on to be a "Delegate to the Event!", which covers events, in my next installment here.

Download the Delegate Example solution

 

Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.