To see how dynamic invocation of delegates works and discuss about the usage scenario
Introduction
In the previous article (http://www.dotnetfunda.com/articles/article1414-invoking-of-delegates-in-net-part-i-.aspx), we have discussed about invocation of delegates with “Invoke” and “BeginInvoke” constructs & also the scenarios where to use what and why. In this discussion we would look at another construct “DynamicInvoke” with reference to delegates again. Dynamic invocation is late-bound invocation and is a feature related to reflection.It also pertains to LCG (Lightweight Code Gen). Calling the delegate directly (i.e. delegate name refer EarlyBinding ) are traditional abilities to invoke at static (compile time) scenario. Using of DynamicInvoke method takes an objects array (params object[] args). This involves setting up stack for a call via code generation (LCG) at runtime using parameters from object[] args array.
Description:
The dynamic invocation of Delegates is essentially dynamic invocation of methods. To explore this invocation on delegates, one needs to use multicast delegates. To brief about multicast delegates, this is a way to combine /compose delegates with the help of ‘+’ (combine) and ‘-‘ (remove). This facilitates the sequential notifications in scenarios where a publish-subscribe/observer pattern would be implemented and in scenarios where assemblies and types are loaded dynamically.
When a subscriber (method) is added to a multicast delegate, the MulticastDelegate class creates a new instance of the delegate type, stores the object reference and the method pointer for the added method into the new instance, and adds the new delegate instance as the next item in a list of delegate instances. In a sense, a linked list of the delegate objects is maintained by the MulticastDelegate class.
Generally such delegates are invoked in order of their addition to multicast delegate but this behaviour can be overridden. Such invocation can lead to issues if any of the invoked method throws an exception or some data is returned through containing delegate.
For delegates that don’t return void or have some data returned, it is advised to enumerate through the invocation list to receive the retuned value.
We would cover early bound invocation in addition to this dynamic invocation.
Method call |
Description |
Invoke |
Late bound mechanism meant for Synchronous operation, if used with asynchronous operation the calling thread would be busy till the asynchronous operation returns and hence there is possibility of deadlock. |
BeginInvoke |
Late bound mechanism meant for Asynchronous operation, if used with asynchronous operation the calling thread will not be busy till the asynchronous operation returns and would continue next operation. |
DynamicInvokea |
Late bound mechanism meant for usage in scenarios where late bound mechanism i.e. dynamic loading of assemblies, sequential notification etc |
Example: Examples are in C# and exercise is done as console application.
We have a class named DynamicInvoking as following which contains 3 different operations namely printing of name, age and gender.
public class DynamicInvoking
{
// The following line causes the compiler to generate a new delegate class named TestDelegate that
// inherits from System.MulticastDelegate.
public delegate void TestDelegate(string msg);
public void PrintName(string name)
{
Console.WriteLine("In PrintName method: The name is " + name);
}
public void PrintAge(string age)
{
Console.WriteLine("In PrintAge method: The age is " + age);
}
public void PrintGender(string gender)
{
Console.WriteLine("In PrintGender method: The gender is " + gender);
}
public void DynamicInvokeMethod(string message)
{
Console.WriteLine("Inside DynamicInvokeMethod ....This is printed before the call to 'DynamicInvoke' ");
//multicast delegates -- use of composition
Console.WriteLine("Inside DynamicInvokeMethod ....Composition of the delegates with '+' operator");
TestDelegate testDelegate = new TestDelegate(PrintName);
testDelegate += new TestDelegate(PrintAge);
testDelegate += new TestDelegate(PrintGender);
//early binding invocation of delegate
Console.WriteLine("Inside DynamicInvokeMethod ....Early bound invocation of delegate'");
testDelegate("Early bound calling the delegate");
// Returns an array of all delegates stored in the linked list of the MulticastDelegate. In this case, the lists will hold three delegates
Delegate[] delegates = testDelegate.GetInvocationList();
Console.WriteLine("Inside DynamicInvokeMethod ....Dynamic invoke would invoke methods associated with all the delegates in sequence'");
testDelegate.DynamicInvoke(new object[] { "'Male'" }); //dynamic invoke would invoke methods asscoiated with the delegate in sequence
Console.WriteLine("Inside DynamicInvokeMethod ....Dynamic invoke for a specific delegate would invoke method 'PrintGender' asscoiated with the specified delegate");
delegates[2].DynamicInvoke(("'Female'"));//want to invoke specific delegate and not invoking in specific order
Console.WriteLine("Inside DynamicInvokeMethod ....This is printed after the call to 'DynamicInvoke' ");
}
}
Console application
class Program
{
static void Main(string[] args)
{
DynamicInvoking dynamicInvoking = new DynamicInvoking();
Console.WriteLine("*************Invoking by DynamicInvoke()**********************");
dynamicInvoking.DynamicInvokeMethod("'Testing Invoke'");
Console.ReadLine();
}
}
Output:
*************Start of Invoking by DynamicInvoke()**********************
Inside DynamicInvokeMethod ....This is printed before the call to 'DynamicInvoke'
Inside DynamicInvokeMethod ....Composition of the delegates with '+' operator
Inside DynamicInvokeMethod ....Early bound invocation of delegate'
In PrintName method: The name is Early bound calling the delegate
In PrintAge method: The age is Early bound calling the delegate
In PrintGender method: The gender is Early bound calling the delegate
Inside DynamicInvokeMethod ....Dynamic invoke would invoke methods associated with all the delegates in sequence'
In PrintName method: The name is 'Male'
In PrintAge method: The age is 'Male'
In PrintGender method: The gender is 'Male'
Inside DynamicInvokeMethod ....Dynamic invoke for a specific delegate would invoke method 'PrintGender' asscoiated with the specified delegate
In PrintGender method: The gender is 'Female'
Inside DynamicInvokeMethod ....This is printed after the call to 'DynamicInvoke'
*************End of Invoking by DynamicInvoke()**********************
Conclusion
The output clearly demonstrates that the mechanism of dynamic invocation for multicast delegates. First we have composition for multicast delegate and we call such delegate which results into sequential calling of methods in order of their composition. Two implementations for dynamicInvoke are shown one for sequential invocation and other for invoking specific delegate from the linked list in the multicast delegates. Such dynamic invocation i.e. late bound can have performance issues but have scope for optimization. This can be used in conjunction with reflection abilities (dynamic loading of assemblies and types) or for implementation of publisher subscriber patterns (through multicast delegates) i.e. event propagation.
Hope this helps to understand multicast delegates, DynamicInvoke and their usage.
References:
http://msdn.microsoft.com/en-us/library/ms173175(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/ms173175(v=VS.100).aspx
http://www.codeproject.com/KB/cs/dynamicmethoddelegates.aspx