Search code examples
c#.netdelegatesinvokedynamic-invoke

Difference Between Invoke and DynamicInvoke


What is the difference between Invoke and DynamicInvoke in delegates? Please give me some code example which explain difference between that two methods.


Solution

  • 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);