Delegates are a special kind of reference type, designed with the specific purpose of representing function pointers. All delegates are derived from the [mscorlib]System.MulticastDelegate class, which in turn is derived from the [mscorlib]System.Delegate class. Because delegates themselves are sealed, no types can be derived from them.

Limitations imposed on the structure of a delegate are as strict as those imposed on the enumerator structure. Delegates have no fields, events, or properties. They can have only member methods, either two or four of them, and the names and signatures of these methods are predefined.

Two mandatory methods of a delegate are the instance constructor (.ctor) and Invoke. The instance constructor returns void (as all instance constructors do) and takes two parameters: the object reference to the type defining the method being delegated and the integer value of the function pointer to the managed method being delegated. (See Chapter 9 for details about instance constructors.)

This leads to a question: If we can get a function pointer per se, why do we need delegates at all? Why not use the function pointers directly? We could, but then we would need to introduce fields or variables of function pointer types to hold these pointers—and function pointer types are considered a security risk and deemed unverifiable. If a module is unverifiable, it can be executed only from a local drive in full trust mode, when all security checks are disabled. Another drawback is that managed function pointers cannot be marshaled to unmanaged function pointers when calling unmanaged methods, whereas delegates can be. (See Chapter 15 for information on managed and unmanaged code interoperation.)

Delegates are secure, verifiable, and type-safe representations of function pointers and as such are preferable over function pointer types. Besides, delegates can offer additional useful features, as I’ll describe in a moment.

The second mandatory method (Invoke) must have the same signature as the delegated method. Two mandatory methods (.ctor and Invoke) are sufficient to allow the delegate to be used for synchronous calls, which are the usual method calls when the calling thread is blocked until the called method returns. The first method (.ctor) creates the delegate instance and binds it to the delegated method. The Invoke method is used to make a synchronous call.

Delegates also can be used for asynchronous calls, when the called method is executed on a separate thread created by the common language runtime for this purpose and does not block the calling thread. So that it can be called asynchronously, a delegate must define two additional methods, BeginInvoke and EndInvoke.

BeginInvoke is a thread starter. It takes all the parameters of the delegated method plus two more: a delegate of type [mscorlib]System.AsyncCallback representing a callback method that is invoked when the call completes, and an object we choose to indicate the final status of the call thread. BeginInvoke returns an instance of the interface [mscorlib]System.IAsyncResult, carrying the object we passed as the last parameter. Remember that because interfaces, delegates, and objects are reference types, when we say “takes a delegate” or “returns an interface,” we actually mean a reference.

If we want to be notified immediately when the call is completed, we must specify the AsyncCallback delegate. The respective callback method is called upon completion of the asynchronous call. This event-driven technique is the most widely used way to monitor the asynchronous calls.

We might choose another way to monitor the status of the asynchronous call thread: polling from the main thread. The returned interface has the method bool get_IsCompleted( ), which returns true when the asynchronous call is completed. We can call this method from time to time from the main thread to find out whether the call is finished.

We can also call another method of the returned interface, get_AsyncWaitHandle, which returns a wait handle, an instance of the [mscorlib]System.Threading.WaitHandle class. After we get the wait handle, we can monitor it any way we please (similar to the use of the Win32 APIs WaitForSingleObject and WaitForMultipleObjects). If you are curious, disassemble Mscorlib.dll and take a look at this class.

Of course, if we have chosen to employ a polling technique, we can forgo the callback function and specify null instead of the System.AsyncCallback delegate instance.

The EndInvoke method takes the [mscorlib]System.IAsyncResult interface, returned by BeginInvoke, as its single argument and returns void. Because this method waits for the asynchronous call to complete, blocking the calling thread, calling it immediately after BeginInvoke is equivalent to a synchronous call using Invoke. EndInvoke must be called eventually in order to clear the corresponding runtime threading table entry, but it should be done when we know that the asynchronous call has been completed.

All four methods of a delegate are virtual and runtime-implemented. When defining a delegate, we can simply declare the methods without providing implementation for them, as shown here:

.class public sealed MyDelegate     extends [mscorlib]System.MulticastDelegate  {    .method public hidebysig instance       void .ctor(object MethodsClass,                   native unsigned int MethodPtr)          runtime managed { }    .method public hidebysig virtual instance        int32 Invoke(void* Arg1, void* Arg2)           runtime managed { }    .method public hidebysig newslot virtual instance        class [mscorlib]System.IAsyncResult            BeginInvoke(void* Arg1, void* Arg2,                      class [mscorlib]System.AsyncCallback callBkPtr,                      objectruntime managed { }    .method public hidebysig newslot virtual instance        void EndInvoke(class [mscorlib]System.IAsyncResult res)           runtime managed { } }

Inside Microsoft. NET IL Assembler
Inside Microsoft .NET IL Assembler
ISBN: 0735615470
EAN: 2147483647
Year: 2005
Pages: 147

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: