Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Delegates and their role in Events in C# .NET

0.00/5 (No votes)
13 May 2009 1  
A simple delegates example.

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)
{
    //Code Usage:
    //Use one block and comment other blocks.
    //Block1 explains simple use of delegate
    //It creates a local varaible of OpeartionDelegate and assign it
    //Subtract method of MathOperations
    //Block2 explains passing delegate as parameter to a method
    //It calls DoOperation method which executes the input delegate
    //Block3 explains use of anonymous delegate
    //This is a backbone for LINQ lambda functors

    //Block1 starts
    int value1, value2;
    int.TryParse(firstValueTextBox.Text, out value1);
    int.TryParse(secondValueTextBox.Text, out value2);
    OperationDelegate operation = MathOperations.Add;
    //Add method is assigned to operation delegate
    resultTextBox.Text = operation(value1, value2).ToString();
    //Block1 ends

    //Block2 starts
    DoOperation(MathOperations.Add);
    //Add method is passed as method parameter. 
    //This is possible because Add method signature is int 
    //XYZ(int,int) same as OperationDelegate
    //Block2 ends

    //Block3 starts
    DoOperation(delegate(int v1, int v2) { return v1 + v2; });
    //here instead of passing some method an anonymous delegate is
    // passed as input parameter
    //Signature of anonymous delegate is same as OperationDelegate
    //Block3 ends
}

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 ints 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:

//Declare a delegate returning void
public delegate void OperationDelegate();
//instance declaration
OperationDelegate Operate;
//attach a method SomeMethodReturningVoid
Operate += SomeMethodReturningVoid;
//attach another method
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);
//delegate which returns base class object is Covariance delegate

//create instance of delegate (Note: DelegateUtility.GetInstance method)
//returns derived class instance depend on input parameters)
CovarianceDelegate covarinceDelegateInstance = 
  new CovarianceDelegate(DelegateUtility.GetInstance);

//execute delegate instance returning base class instance
BaseClass instance = covarinceDelegateInstance("DerivedClass1");

//execute work method of instance
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);
//delegate which accepts base class object 
//as input parameter is Contravariance delegate. 

ContravarianceDelegate contravarianceDelegateInstance = 
   new ContravarianceDelegate(DelegateUtility.DoWork);

//execute contravariance delegate by passing it derived class instance.
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.

DelegateIssue.jpg

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!!!

//Delegate defination
public delegate void OperationDelegate();
//event declaration as private variable and public property
private event OperationDelegate _operate;

public event OperationDelegate Operate 
{
  add { _operate += value; } 
  remove { _operate -= value; } }
  //wiring event using underneath delegate
  _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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here