Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between calling a delegate directly, using DynamicInvoke, and using DynamicInvokeImpl?

Tags:

c#

delegates

The docs for both DynamicInvoke and DynamicInvokeImpl say:

Dynamically invokes (late-bound) the method represented by the current delegate.

I notice that DynamicInvoke and DynamicInvokeImpl take an array of objects instead of a specific list of arguments (which is the late-bound part I'm guessing). But is that the only difference? And what is the difference between DynamicInvoke and DynamicInvokeImpl.

like image 442
Jason Baker Avatar asked May 31 '09 19:05

Jason Baker


1 Answers

The main difference between calling it directly (which is short-hand for Invoke(...)) and using DynamicInvoke is performance; a factor of more than *700 by my measure (below).

With the direct/Invoke approach, the arguments are already pre-validated via the method signature, and the code already exists to pass those into the method directly (I would say "as IL", but I seem to recall that the runtime provides this directly, without any IL). With DynamicInvoke it needs to check them from the array via reflection (i.e. are they all appropriate for this call; do they need unboxing, etc); this is slow (if you are using it in a tight loop), and should be avoided where possible.

Example; results first (I increased the LOOP count from the previous edit, to give a sensible comparison):

Direct: 53ms Invoke: 53ms DynamicInvoke (re-use args): 37728ms DynamicInvoke (per-cal args): 39911ms 

With code:

static void DoesNothing(int a, string b, float? c) { } static void Main() {     Action<int, string, float?> method = DoesNothing;      int a = 23;     string b = "abc";     float? c = null;     const int LOOP = 5000000;      Stopwatch watch = Stopwatch.StartNew();     for (int i = 0; i < LOOP; i++) {         method(a, b, c);     }     watch.Stop();     Console.WriteLine("Direct: " + watch.ElapsedMilliseconds + "ms");      watch = Stopwatch.StartNew();     for (int i = 0; i < LOOP; i++) {         method.Invoke(a, b, c);     }     watch.Stop();     Console.WriteLine("Invoke: " + watch.ElapsedMilliseconds + "ms");      object[] args = new object[] { a, b, c };     watch = Stopwatch.StartNew();     for (int i = 0; i < LOOP; i++) {         method.DynamicInvoke(args);     }     watch.Stop();     Console.WriteLine("DynamicInvoke (re-use args): "          + watch.ElapsedMilliseconds + "ms");      watch = Stopwatch.StartNew();     for (int i = 0; i < LOOP; i++) {         method.DynamicInvoke(a,b,c);     }     watch.Stop();     Console.WriteLine("DynamicInvoke (per-cal args): "          + watch.ElapsedMilliseconds + "ms"); } 
like image 176
Marc Gravell Avatar answered Sep 24 '22 03:09

Marc Gravell