Difference Between Invoke and DynamicInvoke

When you have a delegate instance, you might know the exact type, or you might just know that it is a Delegate. If you know the exact type, you can use Invoke, which is very fast – everything is already pre-validated. For example:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

However! If you just know that it is Delegate, it has to resolve the parameters etc manually – this might involve unboxing, etc – a lot of reflection is going on. For example:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

Note I’ve written the args long hand to make it clear that an object[] is involved. There are lots of extra costs here:

  • the array
  • validating the passed arguments are a “fit” for the actual MethodInfo
  • unboxing etc as necessary
  • reflection-invoke
  • then the caller needs to do something to process the return value

Basically, avoid DynamicInvoke when-ever you can. Invoke is always preferable, unless all you have is a Delegate and an object[].

For a performance comparison, the following in release mode outside of the debugger (a console exe) prints:

Invoke: 19ms
DynamicInvoke: 3813ms

Code:

Func<int,int> twice = x => x * 2;
const int LOOP = 5000000; // 5M
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.Invoke(3);
}
watch.Stop();
Console.WriteLine("Invoke: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.DynamicInvoke(3);
}
watch.Stop();
Console.WriteLine("DynamicInvoke: {0}ms", watch.ElapsedMilliseconds);

Leave a Comment