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

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.

Leave a Comment