0% found this document useful (0 votes)
42 views9 pages

Delegates and Events

This document discusses delegates and events in C#. Delegates allow objects to call back other objects by encapsulating method references. They provide a safer way to implement callbacks compared to function pointers in C/C++ by including type information. Delegates have four main steps - declaration, defining callable methods, instantiation by matching a method signature, and invocation to indirectly call the referenced method. Events use delegates to allow objects to notify other objects of events.

Uploaded by

Ramya Pr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views9 pages

Delegates and Events

This document discusses delegates and events in C#. Delegates allow objects to call back other objects by encapsulating method references. They provide a safer way to implement callbacks compared to function pointers in C/C++ by including type information. Delegates have four main steps - declaration, defining callable methods, instantiation by matching a method signature, and invocation to indirectly call the referenced method. Events use delegates to allow objects to notify other objects of events.

Uploaded by

Ramya Pr
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

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.

Creating and using delegates involve four steps. They include:

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:

modifies delegate return_type delegate_name(parameters);

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:

● new ● public ● protected ● internal ● private

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.

Some examples of delegates are:

delegate void SimpleDelegate( );

delegate int MathOperation(int x, int y);

public delegate int CompareItems(object o1, object o2);

private delegate string GetAString( );

delegate double DoubleOperation(double x);

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

● Outside all classes

● As the top-level object in a namespace

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

● what type of object the method is being called against, and

● whether the method is a static or an instance method.

For instance, the delegate

delegate string GetAString( )

can be made to refer to the method ToString( ) using an int object N as follows:

....

....

int N = 100

GetAString s1 = new GetAString(N.ToString);


The delegate

delegate void Delegate1();

can encapsulate references to the following methods:

public void F1( ) //instance method

Console.WriteLine(“F1”);

static public void F2( ) //static method

Console.Writeline(“F2”);

Similarly, the delegate

delegate double MathOp(double x, double y);

can refer to any of the following methods:

public static double Multiply(double a, double b)

return (a*b);

public double Divide(double a, double 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.

Consider the following code:

//delegate declaration

delegate int ProductDelegate (int x, int y);

class Delegate

static float Product (float a, float b) //signature not match

return ( a * b);

static int Product (int a, int b) //signature matches

return (a * b);

//delegate instantiation

ProductDelegate p = new ProductDelegate(Product);

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.

Consider another example code:

//delegate declaration

delegate void DisplayDelegate( );

class A

//delegate method

public void DisplayA ( ) //instance method

Console.WriteLine(“Display A”);

class B

{
//delegate method

static public void DisplayB( ) //static method

Console.WriteLine(“Display B”);

....

....

// delegate instance

A a = new A( ); //create object a

DisplayDelegate d1 = new DisplayDelegate(a.DisplayA);

....

....

//Another delegate instance

DisplayDelegate d2 = new DisplayDelegate(B.DisplayB);

....

....

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).

Invocation takes the following form:

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.

Example: delegate1(x, y); //void delegate

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.

Example: double result = delegate2(2.56, 45.73);

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

delegate int ArithOp(int x, int y);

class MathOperation

public static int Add(int a, int b)

return (a + b);

public static int Sub(int a, int b)

return (a – b);

class DelegateTest

public static void Main( )

//delegate instances

ArithOp operation1 = new ArithOp (MathOperation.Add);

ArithOp operation2 = new ArithOp(MathOperation.Sub);

//invoking delegates

int result1 = operation1(200, 100);

int result2 = operation2(200,100);

Console.WriteLine(“Result1 = ” + result1);

Console.WriteLine(“Result2 = ” + result2);

The output of Program is


Result 1 = 300

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.

It is also allowed to use delegate objects as method parameters. For instance:

ProcessMethod(operation[0], 200, 100);

is valid. This statement invokes the method ProcessMethod using three parameters including the delegate
object operation1. The ProcessMethod would be defined as under:

static void ProcessMethod (ArithOp operation, int x, int y)

int result1 = operation(x,y);

Console.WriteLine(“Result1 = ” + result);

When operation [0] is passed as a parameter, the invocation

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:

modifier event_type event-name;


The modifier may be new, a valid combination of the four access modifiers, and a valid combination
of static, virtual, override, abstract and sealed. The type of an event declaration must be a delegate
type and the delegate must be as accessible as the event itself. The event-name is any valid C#
variable name. event is a keyword that signifies that the event-name is an event.

Examples of event declaration are:


public event EventHandler Click;
public event RateChange Rate;
EventHandler and RateChange are delegates and Click and Rate are events.
Since events are based on delegates, we must first declare a delegate and then declare an instance of
the delegate using the keyword event.
Program: illustrates a simple implementation of an event handler.
using System;
public delegate void Edelegate(string str);

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( );

EventTest et = new EventTest( );


ec.Status += new EDelegate(et.EventCatch);
ec.TriggerEvent( );
}
public void EventCatch(string str)

{
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.

You might also like