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