Where Are Clr-Defined Methods Like [Delegate].Begininvoke Documented

Where are CLR-defined methods like [delegate].BeginInvoke documented?

The Control.Begin/End/Invoke() and Dispatcher.Begin/End/Invoke() methods have identical names and somewhat similar behavior to a delegate's Begin/End/Invoke() methods but it is certainly best to scrap the idea that they are the same. The most important difference is that a delegate's methods are type-safe, something that's completely missing from the Control and Dispatcher versions. Runtime behavior is very different as well.

The rules that govern a delegate are spelled out in detail in the CLI spec, ECMA 335, chapter II.14.6. It is best to read the chapter, I'll just give a synopsis.

A delegate declaration is transformed into a class that inherits from MulticastDelegate (not Delegate as specified in the CLI spec). That class always has exactly 4 members, their runtime implementation is provided by the CLR:

  • a constructor that takes an object and an IntPtr. The object is the Delegate.Target, the IntPtr is the address of the target method, Delegate.Method. These members are used later when you invoke the delegate, the Target property supplies the this reference if the method to which the delegate is bound is an instance method, null for a static method. The Method property determines which method gets invoked. You don't specify these arguments directly, the compiler supplies them when you use the new operator or subscribe an event handler with the += operator. With lots of syntax sugar in the case of events, you don't have to use the new operator explicitly.

  • an Invoke() method. The arguments of the method are dynamically generated and match the delegate declaration. Calling the Invoke() method runs the delegate target method on the same thread, a synchronous call. You rarely use it in C#, you just use the syntax sugar that allows a delegate object to be invoked by just using the object name, followed by parentheses.

  • a BeginInvoke() method, provides a way to make an asynchronous call. The method quickly completes while the target method is busy executing, similar to ThreadPool.QueueUserWorkItem but with type-safe arguments. The return type is always System.IAsyncResult, used to find out when the asynchronous call is completed and supplied to the EndInvoke() method. First argument is an optional System.AsyncCallback delegate object, it's target will automatically be called when the asynchronous call is complete. Second argument is an optional object, it will be passed as-is to the callback, useful to keep track of state. Additional arguments are dynamically generated and match the delegate declaration.

  • an EndInvoke() method. It takes a single argument of type IAsyncResult, you must pass the one you got from BeginInvoke(). It completes the asynchronous call and releases resources.

Any additional methods you see on a delegate object are the ones that are inherited from the base classes, MulticastDelegate and Delegate. Like DynamicInvoke() and GetObjectData().

Asynchronous calls are the tricky ones and you rarely need to use them. They are in fact not available in .NETCore targets, like Silverlight. The delegate target method runs on an arbitrary thread-pool thread, just like Threadpool.QueueUserWorkItem() does. Any unhandled exception it might throw is captured and terminates the thread but not your program. You must call EndInvoke(), not doing so will cause a resource leak for 10 minutes. If the target method threw an exception then it will be re-raised when you call EndInvoke(). You have no control over the thread-pool thread, there is no way to cancel or abort it. The Task or Thread classes are better alternatives.

MSDN is relevant, the methods of a delegate type are not documented. It assumes you know what they do and what they look like from the specification and the delegate declaration.

Where is declaration of invoke method in Delegate class?

When you create a delegate, the compiler at compile time generates a class inheriting from MulticastDelegate, adding three methods to the class: BeginInvoke, EndInvoke and Invoke. You can easily see it using using ILSpy and the likes.

That is why you cant see it while looking in the Delegate class

This is what MSDN has to say:

MulticastDelegate is a special class. Compilers and other tools can derive from this class, but you cannot derive from it explicitly. The same is true of the Delegate class.

In addition to the methods that delegate types inherit from MulticastDelegate, the common language runtime provides two special methods: BeginInvoke and EndInvoke.

A MulticastDelegate has a linked list of delegates, called an invocation list, consisting of one or more elements. When a multicast delegate is invoked, the delegates in the invocation list are called synchronously in the order in which they appear. If an error occurs during execution of the list then an exception is thrown

Where exactly is SomeDelegate.Invoke implemented and how is it wired to the delegate classes

So, here is how the voodoo magic works (from what I found by glancing over the sources for an hour):

  1. At some time, the method table for the SomeDelegate class is populated and the runtime stumbles upon the Invoke method.
  2. The PreStubWorker (vm\prestub.cpp) is called, which calls DoPrestub, which calls MakeStubWorker
  3. The MakeStubWorker sees that the method is runtime-implemented (pMD->IsEEImpl), asserts that the method table (why ask the method table?) looks like a delegate and calls COMDelegate::GetInvokeMethodStub (vm\comdelegate.cpp) to create the stub.
  4. The COMDelegate::GetInvokeMethodStub method (vm\comdelegate.cpp) calls COMDelegate::TheDelegateInvokeStub which calls the EmitDelegateInvoke and EmitMulticastInvoke methods.
  5. The StubLinkerCPU::EmitDelegateInvoke and StubLinkerCPU::EmitMulticastInvoke methods are implemented in the vm\i386\stublinkerx86.cpp file (for x86) and vm\ppc\cgenppc.cpp (for PowerPC). These methods are quite short and emit the concrete assembly/CPU-specific implementations of the Invoke methods.
  6. The reference to the method implementation is put to the SomeDelegate's method table.

Asynchronous delegates operation clarification?

Delegate.BeginInvoke uses a threadpool thread, just like QueueUserWorkItem. The difference is that it implements the APM pattern, which allows the caller to use a WaitHandle to wait for the call to finish, and also supply a callback.

The Begin/End method pair (AKA the Asynchronous Programming Model) can be found in many places, and it is entirely up to the implementer to decide what happens when you call 'begin'. In many cases, a IO completion port is used, which is a very efficient way for waiting for IO to complete. When IO completes, a threadpool thread is used to execute the callback, but it is taken from a different part of the threadpool (and that's why Set{Min,Max}Threads have two numbers.)

As a side note, with .NET 4.5 (and even 4.0) it is far easier to use Tasks for asynchrony. Many classes have been augmented with methods like 'XXXTaskAsyc' which return a Task object.

C# delegates to Java and asynchronous handling of methods

According to How to asynchronously call a method in Java's answer, FutureTask is a good way in Java to asynchronously run a method. Here's some Java code that runs a task asynchronously (see it run at http://ideone.com/ZtjA5C)

import java.util.*;
import java.lang.*;
import java.util.concurrent.FutureTask;

class Main
{
public static void main (String[] args) throws java.lang.Exception
{
System.out.println("Before");
ExecutorService executorService = Executors.newFixedThreadPool(1);
FutureTask<Object> futureTask = new FutureTask<Object>(new Runnable() {
public void run()
{
System.out.println("Hello async world!");
}
}, null);
System.out.println("Defined");
executorService.execute(futureTask);
System.out.println("Running");
while (!futureTask.isDone())
{
System.out.println("Task not yet completed.");

try
{
Thread.sleep(1);
}
catch (InterruptedException interruptedException)
{
}
}
System.out.println("Done");
}
}

Is it necessary to call EndInvoke in the callback from an EventHandler.BeginInvoke (C# .Net 3.5)

Yes you have to. Only way to find out if the invoked method threw an exception. And to cleanup the remoting state of the call so it can be garbage collected instead of letting it linger for another 10 minutes.



Related Topics



Leave a reply



Submit