CHAPTER 10 DELEGATES, EVENTS, AND LAMBDA EXPRESSIONS
Figure 10-1. The C# delegate keyword represents a sealed class deriving from System.MulticastDelegate
As you can see, the compiler-generated BinaryOp class defines three public methods. Invoke() is
perhaps the key method, as it is used to invoke each method maintained by the delegate object in a
synchronous manner, meaning the caller must wait for the call to complete before continuing on its way.
Strangely enough, the synchronous Invoke() method may not need to be called explicitly from your C#
code. As you will see in just a bit, Invoke()is called behind the scenes when you make use of the
appropriate C# syntax.
BeginInvoke() and EndInvoke() provide the ability to call the current method asynchronously on a
separate thread of execution. If you have a background in multithreading, you know that one of the most
common reasons developers create secondary threads of execution is to invoke methods that require
time to complete. Although the .NET base class libraries supply several namespaces devoted to
multithreaded and parallel programming, delegates provide this functionality out of the box.
Now, how exactly does the compiler know how to define the Invoke(), BeginInvoke(), and
EndInvoke() methods? To understand the process, here is the crux of the compiler-generated BinaryOp
class type (bold italic marks the items specified by the defined delegate type):
sealed class BinaryOp : System.MulticastDelegate
{
public int Invoke(int x, int y);
public IAsyncResult BeginInvoke(int x, int y,
AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
}
First, notice that the parameters and return type defined for the Invoke() method exactly match the
definition of the BinaryOp delegate. The initial parameters to BeginInvoke() members (two integers, in
our case) are also based on the BinaryOp delegate; however, BeginInvoke() will always provide two final
parameters (of type AsyncCallback and object) that are used to facilitate asynchronous method
invocations. Finally, the return type of EndInvoke() is identical to the original delegate declaration and
will always take as a sole parameter an object implementing the IAsyncResult interface.
Let’s see another example. Assume you have defined a delegate type that can point to any method
returning a string and receiving three System.Boolean input parameters:
public delegate string MyDelegate(bool a, bool b, bool c);
361