Delegates in c# .Net
A delegate is
a type that represents references to methods with a particular parameter list
and return type. When you instantiate a delegate, you can associate its
instance with any method with a compatible signature and return type. You can
invoke (or call) the method through the delegate instance.
Delegates are used to pass methods as arguments to other
methods. Event handlers are nothing
more than methods that are invoked through delegates. You create a custom
method, and a class such as a windows control can call your method when a
certain event occurs. The following example shows a delegate declaration:
public delegate int PerformArithmeticsCalculation(int x, int y);
Any method from any
accessible class or struct that matches the delegate type can be assigned to
the delegate. The method can be either static or an instance method. This makes
it possible to programmatically change method calls, and also plug new code into
existing classes.
This ability to refer
to a method as a parameter makes delegates ideal for defining callback methods.
For example, a reference to a method that compares two objects could be passed
as an argument to a sort algorithm. Because the comparison code is in a
separate procedure, the sort algorithm can be written in a more general way.
Properties of Delegates
Delegates
have the following properties:
·
Delegates are similar
to C++ function pointers, but delegates are fully object-oriented, and unlike
C++ pointers to member functions, delegates encapsulate both an object instance
and a method.
·
Delegates allow methods
to be passed as parameters.
·
Delegates can be used
to define callback methods.
·
Delegates can be
chained together; for example, multiple methods can be called on a single
event.
·
Methods do not have to
match the delegate type exactly.
·
C# version 2.0
introduced the concept of anonymous
methods, which allow code blocks to be passed as
parameters in place of a separately defined method. C# 3.0 introduced lambda
expressions as a more concise way of writing inline code blocks. Both anonymous
methods and lambda expressions (in certain contexts) are compiled to delegate
types. Together, these features are now known as anonymous functions. For more
information about lambda expressions, see Lambda expressions.
Using Delegates in C#
A delegate is a type that
safely encapsulates a method, similar to a function pointer in C and C++.
Unlike C function pointers, delegates are object-oriented, type safe, and
secure. The type of a delegate is defined by the name of the delegate. The following
example declares a delegate named DelNaija that can encapsulate a method that
takes a string as an argument and returns void:
public delegate void DelNaija(string message);
A delegate object is
normally constructed by providing the name of the method the delegate will
wrap, or with an anonymous function. Once a delegate is instantiated, a method call made to
the delegate will be passed by the delegate to that method. The parameters
passed to the delegate by the caller are passed to the method, and the return
value, if any, from the method is returned to the caller by the delegate. This
is known as invoking the delegate. An instantiated delegate can be invoked as
if it were the wrapped method itself. For example:
// Create a method for a
delegate.
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
public static void Main()
{
// Instantiate
the delegate.
DelNaija handler = DelegateMethod;
// Call the
delegate.
handler("Hello World");
}
Delegate types are
derived from the Delegate class in the .NET Framework. Delegate types are sealed—they cannot be derived from— and it is not possible to
derive custom classes from Delegate.
Because the instantiated delegate is an object, it can be passed as a
parameter, or assigned to a property. This allows a method to accept a delegate
as a parameter, and call the delegate at some later time. This is known as an
asynchronous callback, and is a common method of notifying a caller when a long
process has completed. When a delegate is used in this fashion, the code using
the delegate does not need any knowledge of the implementation of the method
being used. The functionality is similar to the encapsulation interfaces
provide.
When to Use Delegates Instead of Interfaces
Both delegates
and interfaces enable a class designer to separate type declarations and
implementation. A given interface can
be inherited and implemented by any class or struct.
A delegate can be
created for a method on any class, as long as the method fits the method
signature for the delegate. An interface reference or a delegate can be used by
an object that has no knowledge of the class that implements the interface or
delegate method. Given these similarities, when should a class designer use a
delegate and when should it use an interface?
Use a delegate in the
following circumstances:
·
An
event-base design pattern is used.
·
It
is desirable to encapsulate a static method.
·
The
caller has no need to access other properties, methods, or interfaces on the
object implementing the method.
·
Easy
composition is desired.
·
A
class may need more than one implementation of the method.
Use an interface in the
following circumstances:
·
There
is a group of related methods that may be called.
·
A
class only needs one implementation of the method.
·
The
class using the interface will want to cast that interface to other interface
or class types.
·
The
method being implemented is linked to the type or identity of the class: for
example, comparison methods.
One good example of using a single-method interface instead of a
delegate is IComparable or the generic version, IComparable<T>. IComparable declares the CompareTo method,
which returns an integer that specifies a less than, equal to, or greater than
relationship between two objects of the same type. IComparable can be used as the basis
of a sort algorithm. Although using a delegate comparison method as the basis
of a sort algorithm would be valid, it is not ideal. Because the ability to
compare belongs to the class and the comparison algorithm does not change at
run time, a single-method interface is ideal.
Comments
Post a Comment