How expensive is a delegate call vs a direct function call? The delegate call is actually pretty fast. The delegate typically stores the function and the calling target. When we invoke the delegate, the JIT will retrieve the function pointer and the target and complete the call. You can see from below example.

Here is the C# code

    public class CallDelegate

    {

        [MethodImpl(MethodImplOptions.NoInlining)]

        public static void Run()

        {

            Foo();          

            RetVoid f1 = new RetVoid(Foo);

            f1();           /// Delegate invoke

        }

 

        [MethodImpl(MethodImplOptions.NoInlining)]

        public static void Foo()

        {

            Console.WriteLine("foo");

        }

}

 

   L_0000: nop

    L_0001: call void JitBlog.CallDelegate::Foo()

    L_0006: nop

    L_0007: ldnull

    L_0008: ldftn void JitBlog.CallDelegate::Foo()

    L_000e: newobj instance void JitBlog.RetVoid::.ctor(object, native int)       // Build the delegate objiect

    L_0013: stloc.0

    L_0014: ldloc.0

    L_0015: callvirt instance void JitBlog.RetVoid::Invoke()   // Delegate invoke

    L_001a: nop

L_001b: ret

 

 Here is the disassmbly

 

            call    [CallDelegate.Foo()]

            nop

            mov     ECX, 0x1f336c8                 //Type of delegate

            call    CORINFO_HELP_NEWSFAST_CHKRESTORE

            mov     ESI, EAX

            mov     EAX, 0x1f3c090

            push    EAX

            push    0x4220f8       // Delegate stub

            mov     ECX, ESI

            xor     EDX, EDX

            call    MulticastDelegate.CtorOpened(ref,int,int)

            nop

            mov     EDI, ESI

            mov     ECX, EDI

            mov     EAX, dword ptr [ECX+12]      // Retrieve the function pointer from the Delegate

            mov     ECX, gword ptr [ECX+4]       // Retrieve the target object address from the target

            call    EAX                                          // complete the call