Delegates in C# is one of those things that you NEED to know if you want to extend your knowledge of C#. You’ll find it used in a number of places from events to LINQ. This article introduces the fundamental elements of delegates, as introduced in C# 1.0.
Method Signature
Just before looking at delegates, there’s one simple term to define: ‘Method Signature’. Method Signature describes the return type and parameter types of a method. It doesn’t matter what the method, or the parameters, are called. It’s the types that are important. Moving on …
Types vs Instances
The first thing to know is that delegates come in two flavours: Types and Instances, and it’s important to understand the difference.
Delegate Type
A Delegate Type is a reference type, just like Class or Interface. The difference is, it only describes a single method. Here’s an example where we declare a Delegate Type called PerformCalc
public delegate int PerformCalc(int x, int y);
This looks exactly like a method, but with the keyword delegate inserted. The method signature here describes a method that accepts two parameters of type integer and returns an integer. Any method that has this signature is compatible with this delegate type. Note also that when you declare a delegate type, it inherits from System.Delegate and System.MulticastDelegate both of which provide a number of methods to your delegate.
Delegate Instance
We instantiate a delegate instance using this expression:
new delegate-type ( expression )
Expression can refer to a static method (ie: StaticClass.StaticMethod) or an instantiated object method (ie: ObjectName.Method), but note that the object MUST be instantiated at the point of assignment.
Using our PerformCalc example above then, we create the delegate instance like this:
PerformCalc myCalc = new PerformCalc(CalculateSquare)
where CalculateSquare is a method whose signature is compatible with the delegate type, such as the example below:
private int CalculateSquare(int Operand1, int Operand2) { // Some interesting Calculation }
nb: Note that I have declared the method CalculateSquare as private whereas the delegate PerformCalc is declared as public. This is perfectly acceptable as the visibility is not part of the method signature.
Having created my Delegate Instance, I can now use it wherever I would have used the CalculateSquare method, using the Invoke method. For example:
Console.WriteLine(“Answer: {0}”, myCalc.Invoke(3, 6));
Though C# gives us a shortcut whereby we can miss out the call to invoke altogether:
Console.WriteLine(“Answer: {0}”, myCalc(3, 6));
Multiple Delegates
A delegate instance can consist of more than one method to be called. To add another method to a delegate instance, use the Combine method (which is inherited from the System.Delegate class). To remove a method, use the Remove method. C# makes using these methods even easier by enabling the -, +, += and -= operators. In our example, if we had another method called CalculateArea that has a compatible method signature, we could add it to our delegate instance in either of these two ways:
myCalc.Combine(myCalc, myCalcArea) // or myCalc += myCalcArea
Using Delegates
That’s all the theory needed to understand the foundation of delegates in C# 1.0. Here’s where you might use it:
Example 1:
Let’s say you had created a custom class that contained a list of items. These items are large and complex and there are many ways in which the class user might want to sort the list based on the contents of the items.
You could provide a whole series of overloaded sort methods to address this. Alternatively, you could declare a single Delegate that enables the class user to create their own sort method and pass that in to the class. There’s a great example of using delegates to perform sorting on MSDN.
Example 2:
You write a class, let’s call it StockMonitor, that monitors stock prices. When stocks go above or below a threshold, StockMonitor raises an alert and stores the name of the affected stock in a list accessible via a public property.
If you use this class elsewhere in your code, you’ll need to poll it regularly to see if any stock you’re interested in has triggered an alert. Not very efficient, especially as it may take weeks or months for a stock to break a threshold.
You could easily improve this by adding a method to your StockMonitor class that accepts a delegate parameter. Then, when an alert is raised, you simply call the delegate method that was passed in.
ps: If any of this sounds like Events or Publish and Subscribe functionality, you just found another area where Delegates are used.
Example 3:
Microsoft make use of Delegates. Look through the help files for examples of Predicate, Comparison, Action and Func.
And Now for Something Completely Similar …
This article details Delegates in C# 1. It has been developed in each version of C#, all the way up to the current version (Version 5 at time of writing). My next article details the changes introduced in version 2.
The Road to LINQ
This is the first of a number of articles I’m writing to explain the C# features that underpin LINQ. Look for the keyword LINQ in the category list below for more.
Leave a Reply