Contents
- Introduction
- What are
Delegate
s
- Typesafe
Delegat
es
- Declaring, Instantiating and Invoking
Delegate
s
Event
s
- Conclusion
Introduction
Delegate
s & Event
s are often the most ignorant pieces in the .NET Framework. Rumor has it; they instill fear in the curious minds by their sheer complexity. I studied a great deal of articles in an effort to demystify the unknown, but I really found out there wasn't anything colossal here. Through my article, I will try my hand at exploring the nature of Delegate
s & Event
s. Now let’s get down to business.
What are Delegates
If you ask anybody, they would say:
Delegate
s are similar to Function pointers in C/C++.
Well said, but what are function pointers.
Function pointers are the pointer variables that point to a memory address of a function. So invoking that function pointer would call simply call the underlying function.
Definition
- A
Delegate
is a class whose object store references to methods
- A
Delegate
encapsulates a method with a certain signature
We use delegate
s inadvertently in our day-to-day coding.
Refer to the code below:
this.DataGrid1.ItemDataBound += new
System.Web.UI.WebControls.DataGridItemEventHandler(
this.DataGrid1_ItemDataBound);
When we use DataGrid
’s ItemDataBound
event, delegate
s are at work.
DataGrid
’s ItemDataBound
is the event of type DataGridItemEventHandler Delegate
pointing to function DataGrid1_ItemDataBound
.
Do not indulge into this right now as I will come to Events
later on in the article.
Typesafe Delegates
Are Delegates Any Different from their C/C++ Counterparts (Function Pointers)
Yes, delegate
s in .NET Framework are typesafe. This means that Delegate
signature should match that of the function it points to (encapsulates).
You will get a compile-time error if that’s not the case.
On the other hand, a function pointer in C points to a memory location but it knows nothing about the parameters and the return type of the function unlike delegate
s.
Declaring, Instantiating and Invoking Delegates
Declaration
Let’s declare a simple delegate
:
public delegate bool SmartDelegate(string name, int salary);
This delegate
signature signifies that it will encapsulate methods with return type as bool
and parameters as string
and int
.
The function that this delegate
references would look something like this:
public bool Myfunc(string name, int salary)
So What Exactly Happens When a Delegate Declaration is Executed?
A delegate
declaration is a class declaration that mimics a function-like declaration. In other words, a class is defined that is derived from a MulticastDelagate
class and can be actually deciphered as:
public class SmartDelegate : System.MulticastDelegate
Instantiation
SmartDelegate smartDelegate = new SmartDelegate(MyFunc);
Notice how you instantiate a delegate
, just like you would instantiate a class, simply because a delegate
is a class.
You can add to the delegate
s invocation list by using the “+=” operator.
Instantiation of a delegate
includes passing the function name (MyFunc
) in its constructor. Notice, you do not include the round braces of the function.
Excluding the braces simply means passing the address of the function.
Note: An instance of a delegate
can refer to any instance or static
method, provided the signature of the method matches the signature of the delegate
.
Invoking Delegate
Simply call the delegate
instance:
smartDelegate();
So What Happens When You Actually Call the Delegate Instance?
Invoking a delegate
gets translated as follows:
sampleDelegate.Invoke()
The Invoke
function calls the function (MyFunc
) in turn using the address of the function stored in the delegate
instance.
Events
Let’s shift our energy to events.
Event
s are the outcome of an action. Yes, they are but there is more to this Delegate
s & Event
s tale. Infact, my prime reason to write this article was to explore the difference between the two. We could have simply done away with just having delegate
s, but why do we need event
s.
Events are really restricted delegate
s.
Playing with Events
Let’s start by declaring an event
.
public static event SmartDelegate SmartEvent;
Again adding a target to an event
is a similar procedure to that of delegate
s:
SmartEvent += new SmartDelegate(Myfunc);
Comparing Event & Delegate Declarations
public delegate void SmartDelegate();
public SmartDelegate smartDelegate;
public event SmartDelegate smartEvent;
If you compare statement 1 and statement 2, it seems that the event
keyword is only a modifier here. But what does this modifier do?
Let me explain.
Let’s say there is a ClassA
that defines a delegate
field and an event
both based on type SmartDelegate
.
namespace MyExample
{
public delegate void SmartDelegate();
public class ClassA
{
public SmartDelegate smartDelegate;
public event SmartDelegate smartEvent;
public ClassA()
{
}
}
}
Now a certain class Client
accesses just the delegate
field.
namespace MyExample
{
class Client
{
[STAThread]
static void Main(string[] args)
{
ClassA objA = new ClassA();
objA.smartDelegate += new SmartDelegate(MyFunc1);
objA.smartDelegate = new SmartDelegate(MyFunc2);
objA.smartDelegate();
}
public static void MyFunc1()
{
Console.WriteLine("MyFunc1");
}
public static void MyFunc2()
{
Console.WriteLine("MyFunc2");
}
}
Check the output, on console window it will only display:
MyFunc2
Why?
Because statement2
resets the delegate
instance throwing away the statement 1 invocation.
If statement 2 was used with “+=” operators, the output would have been:
MyFunc1
MyFunc2
Let’s rewrite the class Client
by just replacing statement 2 with event
.
namespace MyExample
{
class Client
{
[STAThread]
static void Main(string[] args)
{
ClassA objA = new ClassA();
objA.smartDelegate += new SmartDelegate(MyFunc1);
objA.smartEvent = new SmartDelegate(MyFunc2);
objA.smartEvent();
}
public static void MyFunc1()
{
Console.WriteLine("MyFunc1");
}
public static void MyFunc2()
{
Console.WriteLine("MyFunc2");
}
}
Statement 2 would give a compilation error because an event would put a restriction and not let the delegate
to reset. Using “+=” operator on statement 2 would execute properly.
Therefore, through event
s you can only add/remove from the delegate
’s invocation list. But never reset the delegate
by using “=”.
Also, statement 3 produces an error because you cannot invoke an event
outside the class that defines the event
.
Here, invoking the event
in class Client
is wrong.
Now, I'll modify the classes to run the code properly.
namespace MyExample
{
public delegate void SmartDelegate();
public class ClassA
{
public SmartDelegate smartDelegate;
public event SmartDelegate smartEvent;
public ClassA()
{
}
public void FireEvent()
{
smartEvent();
}
}
}
namespace MyExample
{
class Client
{
[STAThread]
static void Main(string[] args)
{
ClassA objA = new ClassA();
objA.smartDelegate += new SmartDelegate(MyFunc1);
objA.smartEvent += new SmartDelegate(MyFunc2);
objA.smartDelegate();
objA.FireEvent();
}
public static void MyFunc1()
{
Console.WriteLine("MyFunc1");
}
public static void MyFunc2()
{
Console.WriteLine("MyFunc2");
}
}
The output on the console window is as follows:
MyFunc1
MyFunc2
Some Properties that Events Exhibit
Event
s can only be invoked by the class that defined it.
Event
s can be included in interfaces whereas interfaces cannot contain fields of type delegate
.
Event
s cannot reset the delegate
invocation list by using “=” outside its class definitions. Event
s can only add/remove to the handler by using “+=” and “-=” respectively.
Conclusion
Including Event
modifier to the delegate
declaration only lets the adding/removing of the target to the invocation list & constrains its invocation from outside the class that defines it.
This is exactly where
event
s come into the picture and prevent such a situation.