Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why cannot I create a dynamic delegate which has more than one argument using .NET EMIT

There are some definations:

public class Message
{
    public SayType Say(string name)
    {
        Console.Write("Hello," + name );
        return SayType.Name;
    }
    
    public SayType Say(string name,string haha)
    {
        Console.Write("Hello," + name );
        return SayType.Name;
    }
}

public enum SayType
{
    Name
}

And I want to create two dynamic of the two function in class Message.
The first:

DynamicMethod dynamicMethod = 
             new DynamicMethod("Say",typeof(SayType),new Type[]{typeof(object),typeof(object[])});
        var il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg,0); 
        il.Emit(OpCodes.Ldarg,1); 
        il.Emit(OpCodes.Ldc_I4,0);
        il.Emit(OpCodes.Ldelem_Ref);  
        il.Emit(OpCodes.Callvirt,typeof(Message).GetMethods()[0]);
        //[0] refers to the first method 
        il.Emit(OpCodes.Ret); 
        System.Delegate delegates = dynamicMethod.CreateDelegate(typeof(SayDelegate));
        delegates.DynamicInvoke(new Message(), new object[]{"123123"});

It can work normally.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

However, if I create the second delegate like this:

DynamicMethod dynamicMethod = 
             new DynamicMethod("Say",typeof(SayType),new Type[]{typeof(object),typeof(object[])});
        var il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg,0); 
        il.Emit(OpCodes.Ldarg,1); 
        il.Emit(OpCodes.Ldc_I4,0);
        il.Emit(OpCodes.Ldelem_Ref); 
        il.Emit(OpCodes.Ldc_I4,1); 
        il.Emit(OpCodes.Ldelem_Ref); 
        il.Emit(OpCodes.Callvirt,typeof(Message).GetMethods()[1]);
        //[1] refers to the second method 
        il.Emit(OpCodes.Ret); 
        System.Delegate delegates = dynamicMethod.CreateDelegate(typeof(SayDelegate));
        delegates.DynamicInvoke(new Message(), new object[]{"123123","123123"});

It will have some complains:

 ---> System.InvalidProgramException: Common Language Runtime detected an invalid program.
   at Say(Object , Object[] )
   --- End of inner exception stack trace ---

>Solution :

You missed a ldarg.1:

il.Emit(OpCodes.Ldarg, 0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ldelem_Ref);
il.Emit(OpCodes.Ldarg, 1); // <<== this one
il.Emit(OpCodes.Ldc_I4, 1);
il.Emit(OpCodes.Ldelem_Ref);

The trick is to compile and decompile what you want, and look at the IL; in this case we see:

IL_0000: ldarg.0
IL_0001: castclass Message
IL_0006: ldarg.1
IL_0007: ldc.i4.0
IL_0008: ldelem.ref
IL_0009: castclass [System.Runtime]System.String
IL_000e: ldarg.1
IL_000f: ldc.i4.1
IL_0010: ldelem.ref
IL_0011: castclass [System.Runtime]System.String
IL_0016: callvirt instance valuetype SayType Message::Say(string, string)
IL_001b: ret

and compare that to your opcodes (noting that you’re using unsafe coerce, which … I’m not going to advocate for, but I also can’t stop you from doing)

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading