Nuts and bolts
A Delegate is a type which represents a function pointer, and as such it enables you to dynamically wire up a method caller to the target method. It literally delegates a method call from the delegate to the target method(s).
A Delegate Type defines the delegate protocol, or method signature of the target methods:
delegate int NumberCruncher(int a, int b);
a Delegate Instance represents a method which matches the protocol and has been associated with the delegate:
NumberCruncher multiplier = MultiplyNumbers; private int MultiplyNumbers(int a, int b) { return a*b; }
All delegates have multicast capabilities (as they implicitly inherit from System.MulticastDelegate), meaning that multiple target methods can be associated to a single delegate, or more correctly, multiple methods can be associated to a delegate instance. This is achieved by using the += operator:
multiplier += AddNumbers; private int AddNumbers(int a, int b) { return a+b; }
Invoking the delegate will result in all the associated methods executing in the order in which they were added. If the delegate has a return value, only the return value of the last method will the returned, with all other return values discarded.
Removing a method from the list of target methods is done by using the -= operator. The += and -= operators are compiled to the static Combine and Remove methods of the Delegate class.
Plugin Methods
Delegates are handy for plugging dynamic functionality into another method:
public void PerformANumericDuty(int[] values, NumberCruncher cruncher) { //do something here... for(int i = 0; i < values.Length; i++) values[i] = cruncher(values[i], 10) } }
Generic Delegates
Delegates may use generic type parameters:
delegate T GenericDelegate<T>(T arg); GenericDelegate<double> squarer = Square; private double Square(double a){ return a*a; }
Contravariance
Delegates are contravariant, meaning that the delegate type parameters can be more specific than the delegate instance type parameters:
class House : Asset { ... } delegate void SellHouse(House house); ... private void SellAsset(Asset asset){ ... } ... SellHouse houseSeller = SellAsset; ... houseSeller(new House());
Covariance
Delegates are covariant, meaning that the return type of a delegate type can be less specific than the return type of the delegate instance.
class House : Asset { ... } delegate Asset GetAsset(); ... GetAsset getMyHouse = GetHouse(); ... private House GetHouse() { ... } ... Asset myhouse = getMyHouse();