Delegates and Events
Delegates and Events
In object-oriented programming, it is the usual practice for one object to send messages to other objects. However, in
real-life applications, it is quite common for an object to report back to the object that was responsible for sending a
message. This, in effect, results in a two-way conversation between objects. The methods used to call back messages
are known as callback methods.
Languages like C and C++ implement callback techniques using what are known as function pointers. Function
pointers simply represent memory addresses and they do not include ‘type-safe’ information such as
● number of parameters
● types of parameters
● return type
● calling convention
Further, in object-oriented programming, methods rarely exist in isolation. They are usually associated with a class
instance before they can be called. Because of these problems, C# implements the callback technique in a much safer
and more object-oriented manner, using a kind of object called delegate object.
A delegate object is a special type of object that contains the details of a method rather than data. Delegates in C# are
used for two purposes:
● Callback
● Event handling
Delegates
The dictionary meaning of delegate is “a person acting for another person”. In C#, it really means a method acting for
another method. As pointed out earlier, a delegate in C# is a class type object and is used to invoke a method that has
been encapsulated into it at the time of its creation.
1. Delegate declaration
2. Delegate methods definition
3. Delegate instantiation
4. Delegate invocation
A delegate declaration defines a class using the class System.Delegate as a base class. Delegate methods are any
functions (defined in a class) whose signature matches the delegate signature exactly. The delegate instance holds the
reference to delegate methods. The instance is used to invoke the methods indirectly.
An important feature of a delegate is that it can be used to hold reference to a method of any class. The only
requirement is that its signature must match the signature of the method.
Delegate Declaration
A delegate declaration is a type declaration and takes the following general form:
delegate is the keyword that signifies that the declaration represents a class type derived from System.Delegate. The
return-type indicates the return type of the delegate. Parameters identifies the signature of the delegate. The
delegate-name is any valid C# identifier and is the name of the delegate that will be used to instantiate delegate
objects.
The modifier controls the accessibility of the delegate. It is optional. Depending upon the context in which they are
declared, delegates may take any of the following modifiers:
The new modifier is only permitted on delegates declared within another type. It signifies that the delegate hides an
inherited member by the same name.
Although the syntax is similar to that of a method definition (without method body), the use of keyword delegate tells
the compiler that it is the definition of a new class using the System.Delegate as the base class. Since it is a class type,
it can be defined in any place where a class definition is permitted. That is, a delegate may be defined in the following
places:
● Inside a class
Depending on how visible we want the delegate to be, we can apply any of the visibility modifiers to the delegate
definition.
Delegate types are implicitly sealed and therefore it is not possible to derive any type from a delegate type. It is also
not permissible to derive a non-delegate class type from System.Delegate.
Delegate Methods
The methods whose references are encapsulated into a delegate instance are known as delegate methods or callable
entities. The signature and return type of delegate methods must exactly match the signature and return type of the
delegate.
One feature of delegates, as pointed out earlier, is that they are type-safe to the extent that they ensure the matching
of signatures of the delegate methods. However, they do not care
can be made to refer to the method ToString( ) using an int object N as follows:
....
....
int N = 100
Console.WriteLine(“F1”);
Console.Writeline(“F2”);
return (a*b);
return (a/b);
Note that in both the cases, the signature and return type of methods match the signature and type of the delegate.
Delegate Instantiation
Although delegates are of class types and behave like classes, C# provides a special syntax for instantiating their
instances. A delegate-creation-expression is used to create a new instance of a delegate:
new delegate_type(expression)
The delegate-type is the name of the delegate declared earlier whose object is to be created. The expression must be
a method name or a value of a delegate-type. If it is a method name its signature and return type must be the same as
those of the delegate. If no matching method exists, or more than one matching method exists, an error occurs. The
matching method may be either an instance method or a static method. If it is an instance method, we need to specify
the instance as well as the name of the method. If it is a static one, then it is enough to specify the class name and the
method name.
The method and the object to which a delegate refers are determined when the delegate is instantiated and then
remain constant for the entire lifetime of the delegate. It is, therefore, not possible to change them, once the delegate
is created.
It is also not possible to create a delegate that would refer to a constructor, indexer, or user-defined operator.
//delegate declaration
class Delegate
return ( a * b);
return (a * b);
//delegate instantiation
Here, we have two methods with the same name but with different signatures. The delegate p is initialized with the
reference to the second Product method because that method exactly matches the signature and return type of
ProductDelegate. If this method is not present, an error will occur. Note that since the method and the instantiation
statement are within the same class, we simply use the method name for creating the instance.
//delegate declaration
class A
//delegate method
Console.WriteLine(“Display A”);
class B
{
//delegate method
Console.WriteLine(“Display B”);
....
....
// delegate instance
....
....
....
....
The code defines two delegate methods in two different classes. Since class A defines an instance method, an A type
object is created and used with the method name to initialize the delegate object d1. The delegate method defined in
class B is static and therefore the class name is used directly with the method name in creating the delegate object d2.
Delegate Invocation
C# uses a special syntax for invoking a delegate. When a delegate is invoked, it in turn invokes the method whose
reference has been encapsulated into the delegate, (only if their signatures match).
degate_object(parameter_list);
The optional parameters list provides values for the parameters of the method to be used.
● If the invocation invokes a method that returns void, the result is nothing and therefore it cannot be used as an
operand of any operator. It can be simply a statement_expression.
This delegate invokes a method that does not return any value.
● If the method returns a value, then it can be used as an operand of any operator. Usually, we assign the return value
to an appropriate variable for further processing.
This statement invokes a method (that takes two double values as parameters and returns double type value) and
then assigns the returned value to the variable result.
Note: Sometimes the term ‘delegate’ is used to denote both the delegate type and delegate object. We need to be
aware of the context to know which meaning we are using when we talk about delegates.
Using Delegates
Program: illustrates how a delegate is created and used in a program. The program implements two delegate methods
and therefore we need to create two delegate objects to invoke these methods independently.
using System;
//delegate declaration
class MathOperation
return (a + b);
return (a – b);
class DelegateTest
//delegate instances
//invoking delegates
Console.WriteLine(“Result1 = ” + result1);
Console.WriteLine(“Result2 = ” + result2);
Result 2 = 100
In Program we created two delegates of the same type. If we need to implement more delegate methods, we
have to create more delegate objects. In such cases, we may create an array of delegate objects and then use
them in a for loop to invoke the methods. Example:
ArithOp [ ] operation =
{new ArithOp(MathOperation.Add),
new ArithOp(MathOperation.Sub)
};
This creates two delegates, operation[0] to invoke Add method and operation [1] to invoke Sub method.
is valid. This statement invokes the method ProcessMethod using three parameters including the delegate
object operation1. The ProcessMethod would be defined as under:
Console.WriteLine(“Result1 = ” + result);
operation (x,y)
invokes Add method. Similarly, we can pass operation [1] to invoke Sub method.
Events
An event is a delegate type class member that is used by the object or class to provide a notification
to other objects that an event has occurred. The client object can act on an event by adding an event
handler to the event.
Events are declared using the simple event declaration format as follows:
class EventClass
{
//declaration of event
public event Edelegate Status;
public void TriggerEvent( )
{
if(Status != null)
Status (“ Event Triggered”);
}
}
class EventTest
{
public static void Main( )
{
EventClass ec = new EventClass( );
{
Console.WriteLine(str);
}
}
The output of program is
Event Triggered
The above Program declares first a delegate which is used to declare the event Status in the class
EventClass. This class has a method to trigger the event when it occurs. Note that we have to check
the event Status against null because no event might have occurred earlier.
The class EventTest defines, in addition to the Main, a method EventCatch whose signature matches
that of the event. The EventClass is instantiated, and the method is subscribed to the Status event:
ec.Status += new Edelegate(et.EventCatch);
From now on, this method is called when the event is triggered.