Introduction
In this article you will learn about what Delegates are and how to use them in C#.
MSDN says a delegate is "a data structure that refers to a static method or to a class instance and an instance method of that class." That's hard to understand.
A delegate is an object that wraps (encapsulates) a function. The delegate describes the input parameters and return type of the function it wraps. For example:
delegate int DoSomeMath(int x, int y);
DoSomeMath is a delegate that can wrap any function that takes in two int parameters and returns an int.
MSDN says a delegate can refer to a static method. What that means is that a delegate can encapsulate a static method. Here are two static methods:
static int AddThem(int input1, int input2)
{
return input1 + input2;
}
static int MultiplyThem(int input1, int input2)
{
return input1 * input2;
}
These methods have the right signature for my delegate. They each take in two ints and return an int. I can use them like this:
DoSomeMath adder = new DoSomeMath(AddThem);
DoSomeMath multiplier = new DoSomeMath(MultiplyThem);
int output = adder(100, 200) + multiplier(3, 4);
MSDN says a delegate can refer to "a class instance and an instance method of that class." So here's a class:
public class MyMathClass
{
public int AddThem(int input1, int input2)
{
return input1 + input2;
}
}
I can use it like this:
MyMathClass myMath = new MyMathClass ();
DoSomeMath adder = new DoSomeMath(myMath.AddThem);
int result = adder(100, 200);
or like this:
DoSomeMath adder = new DoSomeMath(new MyMathClass().AddThem);
int result = adder(100, 200);
Here is another way to do things using a Func and a lambda expression:
Func<int, int, int> AddThem = (a,b) => a + b;
DoSomeMath adder = new DoSomeMath(AddThem);
int result = adder(100, 200);
That may look more complicated, but it's the same idea. The first line is simply a different way of declaring a static method that takes in two ints and returns their sum. The compiler will convert this into a static method just like the one in my first example.
Why Would I Ever Do That?
Most programmers can go for years without ever using a delegate. Why would I ever want to use one?
The fact is, you can get by without delegates, but sometimes they make life easier. One of the most common situations where we would use a delegate is in an Observer-type design pattern. In this example, the DataFiddler class takes in a collection of NotifyMe delegates:
delegate void NotifyMe(Exception ex);
public class DataFiddler
{
private List<NotifyMe> observerList = new List<NotifyMe>();
public DataFiddler(List<NotifyMe> observers)
{
observerList = observers;
}
public void FiddleData( )
{
try
{
// Do something
}
catch (Exception ex)
{
foreach (NotifyMe observer in observerList)
observer(ex);
}
}
}
Here we have a delegate, NotifyMe, that takes in an Exception. This could be used to wrap a function that will log the Exception, send someone a warning or take other appropriate action.
The DataFiddler class has a List of NotifyMe objects. If the FiddleData( ) method throws an Exception then the Exception is passed to each NotifyMe object. The DataFiddler class doesn't need to know what to do when there's an Exception. It doesn't need to know whether to write to a log or notify someone. Depending on the delegates passed in, it might write to several logs, notify several people and take other actions as well. The program that created the DataFiddler object passes it a List of delegates for the DataFiddler to call.