Friday, January 11, 2013

Delegates in C#



A method that is specified in an interface is implemented with the same name in the
base class. However, such close coupling is not always appropriate. The delegate construct
can be used to break the coupling for this purpose.

A delegate is a type that
defines a method signature. A delegate instance is then able to accept a method of that
signature, regardless of its method name or the type that encapsulates it.
The delegate syntax in C# evolved considerably from Versions 1.0 to 2.0 to 3.0. We
shall concentrate on the 3.0 version, which is the simplest to code. The language has
predefined standard generic delegate types, as follows:

        delegate R Func<R>();
        delegate R Func<A1, R>(A1 a1);
        delegate R Func<A1, A2, R>(A1 a1, A2 a2);
        // ... and up to 16 arguments

where R is the return type and the As and as represent the argument types and names,
respectively. Thus, declaring a delegate instance is now straightforward. For example,
we can define a Request delegate that takes an integer parameter and returns a string:

public Func<int, string> Request;

Next, we can assign an actual method to Request, as in:

Request = Target.Estimate;

The delegate can then be invoked just as any other method would be:

string s = Request(5);

This statement would invoke the Estimate method in the Target class, returning a
string.


Anonymous functions simplify the creation of one-time behavior for delegates. They are
useful when additional behavior is to be added before or after a method is invoked. For
example:

Request = delegate(int i) {
return "Estimate based on precision is " +
(int) Math.Round(Precise (i,3));
};

Here, the method to be invoked is Precise. The parameters are different from the ones
in the delegate, as is the return value. The anonymous function can wrapupthe
changes and assign a “complete solution” to the delegate for later invocation.


Delegates are used extensively in Windows GUI event-driven programming, where
they reflect the need to call back into the user’s code when some event happens.
Mostly, existing code of this type will use an older syntax. Also, because the new Func
delegates must have return types, void delegates must use the original syntax too. Consider
a simple example of wanting to inform one object that input has occurred in
another object (this is part of Example 4-4). We first declare a delegate visible to both
classes:

public delegate void InputEventHandler(object sender, EventArgs e, string s);

Then, in the class where the event is handled, we create an instance of the delegate and
add it to the event object of the class that will receive the event. When creating the delegate,
we indicate the method that it will call (in this case, OnInput):


   visuals.InputEvent += new InputEventHandler(OnInput);

        void OnInput(object sender, EventArgs e, string s)
        {
            // Do something
        }



The signature of OnInput must match that of InputEventHandler, which it does. Now,
in the class where event occurs, we declare the event:


       public event InputEventHandler InputEvent;

and in some method we invoke it:


       public void Input(object source, EventArgs e)
       {
           InputEvent(this, EventArgs.Empty, who);
       }

The action of invoking the InputEvent delegate causes the method currently assigned
to it (here, OnInput) to be invoked. Thus, the callback from one class to the other is
achieved.

More than one method can be associated with a delegate; when such a delegate is
invoked, all its methods are called. Thus, if another object needed to know about input
in the preceding example, it could add its own handler method on to InputEvent using
+=. Event handlers can be removed using -=

No comments:

Post a Comment