Wednesday, October 24, 2007

Introduction of Delegates1


Ø Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked.

Ø Sometimes, however, we don't want to call a function directly - we'd like to be able to pass it to somebody else so that they can call it. This is especially useful in an event-driven system such as a graphical user interface, when I want some code to be executed when the user clicks on a button, or when I want to log some information but can't specify how it is logged.

Ø An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match the delegate's. This makes delegates perfectly suited for "anonymous" invocation.

Ø The signature of a single cast delegate is shown below:
delegate result-type identifier ([parameters]);
Ø result-type: The result type, which matches the return type of the function.
Ø identifier: The delegate name.
Ø parameters: The Parameters, that the function takes.

public delegate void SimpleDelegate ()

This declaration defines a delegate named SimpleDelegate, which will encapsulate any method that takesno parameters and returns no value.

public delegate int ButtonClickHandler (object obj1, object obj2)

This declaration defines a delegate named ButtonClickHandler, which will encapsulate any method that takestwo objects as parameters and returns an int.

Ø A delegate will allow us to specify what the function we'll be calling looks like without having to specify which function to call.
Ø The declaration for a delegate looks just like the declaration for a function, except that in this case, we're declaring the signature of functions that this delegate can reference.
Ø There are three steps in defining and using delegates:

Ø Declaration
Ø Instantiation
Ø Invocation

Ø A very basic example (SimpleDelegate1.cs):
using System;
namespace Akadia.BasicDelegate
// Declaration
public delegate void SimpleDelegate();
class TestDelegate
public static void MyFunc()
Console.WriteLine("I was called by delegate ...");
public static void Main()
// Instantiation
SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);
// Invocation
public delegate [return type] [Delegate Name] ( [list of parameters] );

Ø where [return type] is the return type of the function, [Delegate Name] is the name of this delegate, and [List of parameters] is the list of the parameters in the function you want to point to.
Ø Delegates do differ from the C/C++ concept of function pointers. Here are some of the differences:
Ø Runtime Instantiation vs Static InstantiationDelegates are dynamic structures and are declared at runtime. In C/C++ you needed to know the function ahead of time before you can use the function pointers. In C#, delegates require runtime instantiation. This allows you the opportunity to not only using static methods but methods in class instances as well.
Ø ChainingDelegates don't just point to a single function. Rather they can be thought of as an ordered set of functions where each function in the set as the same function footprint (same return type and same number and types of parameters).]
publid delegate void printFuncs (String name);
public void printToScreen(String name) { ... }
public void printToComPort(String name) { ... }
public void printToPrinter(String name) { ... }
public void dbQuery()
printFuncs print = new printFuncs(printToScreen);

print += new printFuncs(printToComPort);
print += new printFuncs(printToPrinter);

In this example, when you execute the delegate variable print it will in turn call printToScreen, printToComPort, and printToPrinter.NOTE: The order in which you add these functions is important. In the print example above, when delegate variable print is execute, printToScreen will be called first, then printToComPort, then printToPrinter. The functions will not be called in any other order. Also note that if any function in the chain throws an exception, the rest of the chain will not be executed.
Ø Any method that matches the delegate's signature, which consists of the return type and parameters, can be assigned to the delegate.
Ø This ability to refer to a method as a parameter makes delegates ideal for defining callback methods.
Ø Delegates have the following properties:
Ø Delegates are similar to C++ function pointers, but are type safe.
Ø 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 don't need to match the delegate signature exactly. For more information, see Covariance and Contravariance
Ø C# version 2.0 introduces the concept of Anonymous Methods, which permit code blocks to be passed as parameters in place of a separately defined method.
Ø 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
Ø A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an anonymous Method.
Ø 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.
Ø 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 (C# Programming Guide)

Both delegates and interfaces allow 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 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 with 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 they use an interface?
Use a delegate when:
An eventing design pattern is used.
It is desirable to encapsulate a static method.
The caller has no need 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 when:

There are 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 IComparable. IComparable declares the CompareTo method, which returns an integer specifying 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, and while 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 doesn’t change at run-time, a single-method interface is ideal.

No comments: