Introduction
Very often, we face situations where an object needs to perform different operations at different states. And most interestingly, we find the object itself is unaware of the requirement. What happens if we want a method to execute different code at different times? This can be handled using delegates. A delegate is a type safe function pointer. It allows attaching different method bodies for execution.
Declaring a delegate
public delegate void OperationDelegate();
The above delegate accepts no parameters and returns no parameters. If you observe carefully, the delegate signature is similar to any method signature. It only requires using the delegate
keyword as a prefix.
Instantiating a delegate
OperationDelegate operate = new OperationDelegate(MathOperations.Add);
Isn’t it identical to instantiating a class? It accepts a method as the input parameter while instantiating (MathOperations.Add
). Another way of instantiating a delegate is:
OperationDelegate operation = MathOperations.Add;
Wow, it is like assignment!! Refer to SimpleDelegateExample.csproj demonstrating a simple delegate declaration and usage. The addButton_click
and subtractButton_Click
code snippets demonstrate different ways of using the delegate. You can check each approach by commenting out the other. [Each approach is wrapped with Block starts and Block ends].
private void addButton_Click(object sender, EventArgs e)
{
int value1, value2;
int.TryParse(firstValueTextBox.Text, out value1);
int.TryParse(secondValueTextBox.Text, out value2);
OperationDelegate operation = MathOperations.Add;
resultTextBox.Text = operation(value1, value2).ToString();
DoOperation(MathOperations.Add);
DoOperation(delegate(int v1, int v2) { return v1 + v2; });
}
Anonymous methods for delegates
What happens if we want to define custom execution for a delegate, but we don’t have any method matching the same signature? Moreover, we want to write just one odd line(s) of code. Why should then we write a method? We can define anonymous methods. Anonymous methods are similar to inline methods.
delegate(int v1, int v2) { return v1 - v2; }
The above anonymous method accepts two int
s as inputs and returns the subtracted value.
Multicast delegates
A multicast delegate is one which allows the user to attach multiple methods. It should typically return void
. But this is not a thumb rule. We can attach multiple methods to delegates returning a value. In that case, the return value of the last executed method will be stored. E.g., if you define a delegate returning an int
and attach multiple methods to it, then the return value of the delegate will be the value returned by the last executed method. So developers should avoid doing this. [Note: Microsoft doesn’t guarantee the order of execution if multiple methods are attached to a delegate.] The .NET framework has provided EventHandler
as a multicast delegate. The signature of the EventHandler
follows:
public delegate void EventHandler(object sender, EventArgs e)j
A custom multicast delegate:
public delegate void OperationDelegate();
OperationDelegate Operate;
Operate += SomeMethodReturningVoid;
Operate += delegate() { MessageBox.Show("Multicast example"); };
More specialization of delegates
In some cases, attached methods do not have to match the delegate signature exactly. More specifically, when delegates are defined with a signature either accepting a base class or returning a base class, they don’t match with signatures. It’s the magic of inheritance that allows the attached method signature to not match with the signature of the delegate. Let’s see how:
Covariance delegate
When a delegate signature is returning a base variable, it’s called a covariance delegate.
internal delegate BaseClass CovarianceDelegate(string name);
CovarianceDelegate covarinceDelegateInstance =
new CovarianceDelegate(DelegateUtility.GetInstance);
BaseClass instance = covarinceDelegateInstance("DerivedClass1");
instance.Work();
Contravariance delegate
When a delegate accepts a variable of the base class type, it’s called a contravariance delegate:
internal delegate void ContravarianceDelegate(BaseClass instance);
ContravarianceDelegate contravarianceDelegateInstance =
new ContravarianceDelegate(DelegateUtility.DoWork);
contravarianceDelegateInstance(new DerivedClass2());
Issues with delegates
Now consider a scenario. We have a class (classA
) which holds variables and a delegate. Two different classes hold reference to the classA
. Each class attaches their own method to the delegate. During the execution phase, some class encounters a situation where it requires setting the classA
delegate to null
. As a delegate is a function pointer, we can set it to null
. Doing so put the system in a mess. Wondering why? How could other classes come to know that delegate is now set to null
? It cleans other class methods attached to the delegate.
This scenario is described in DelegateIssue.csproj.
Events in .NET
We can avoid the above situation by using event notifications. .NET uses the Publisher Subscriber mechanism to notify events. The .NET event framework underneath uses a delegate as the medium of communication (event handler wirings). The advantage with event based designing is that you (subscriber) can’t set the event to null
. Subscribers can subscribe/unsubsrcibe to an event, but they can’t set it to null
. Only the publisher can do it. Secondly, nobody except the event publisher can raise the event. Sounds great!!!
public delegate void OperationDelegate();
private event OperationDelegate _operate;
public event OperationDelegate Operate
{
add { _operate += value; }
remove { _operate -= value; } }
_data.Operate += this.Operation;
Refer eventExample.csproj for details.
Thanks for reading the article. I hope it is helpful for you. Any suggestions/feedback is welcome.