简体   繁体   中英

C# Emit create dynamic property ToString method

I have a class like below code :

public class MyClass
{
    public int MyProperty1 { get; set; }
}

and I hope to create a dynamic method call tostring

public static string MyProperty1ToString(MyClass o){
    return o.MyProperty1.ToString();
}

IL

MyProperty1ToString:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  callvirt    UserQuery+MyClass.get_MyProperty1
IL_0007:  stloc.0     
IL_0008:  ldloca.s    00 
IL_000A:  call        System.Int32.ToString
IL_000F:  stloc.1     
IL_0010:  br.s        IL_0012
IL_0012:  ldloc.1     
IL_0013:  ret   

so i try to use Emit to create method,but get error

InvalidProgramException : common language runtime detected an invalid program

public class Program
{
    public static void Main()
    {
        var obj = new MyClass() { MyProperty1 = 123 };
        var prop = obj.GetType().GetProperty("MyProperty1");

        var func = GetByPropertyCallToStringFunction<MyClass>(prop);
        var data = func(obj); //InvalidProgramException : common language runtime detected an invalid program
    }

    public static Func<T, string> GetByPropertyCallToStringFunction<T>(PropertyInfo prop)
    {
        var type = prop.DeclaringType;
        var propGetMethod = prop.GetMethod;
        var propType = prop.PropertyType;

        DynamicMethod dynamicMethod = new DynamicMethod($"{prop.Name}_method", typeof(string), new Type[] { type }, type.Module);

        var toStringMethod = propType.GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(p => p.Name == "ToString").First();

        ILGenerator il = dynamicMethod.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Callvirt, propGetMethod);
        il.Emit(OpCodes.Stloc);
        il.Emit(OpCodes.Ldloca_S, 00);
        il.Emit(OpCodes.Call, toStringMethod);
        il.Emit(OpCodes.Stloc_1);
        il.Emit(OpCodes.Br_S, "IL_0012");
        il.Emit(OpCodes.Ldloc_1);
        il.Emit(OpCodes.Ret);

        var invoke = (Func<T, string>)dynamicMethod.CreateDelegate(typeof(Func<T, string>));
        return invoke;
    }
}

Question

how can i get emit runtime compiler details error message?
I have no idea when only InvalidProgramException


Test Link : C# Emit to create dynamic Property ToString method | C# Online Compiler | .NET Fiddle

Got it. Further to the fact that branch labels must be explicitly declared (which ckuri already correctly discovered), you also have to declare locals - including their type - before referencing them.

Here's the code:

var propType = prop.PropertyType;
var propGetMethod = prop.GetMethod;

ILGenerator il = dynamicMethod.GetILGenerator();
LocalBuilder local0 = il.DeclareLocal(typeof(propType));
LocalBuilder local1 = il.DeclareLocal(typeof(string));
Label label0 = il.DefineLabel();

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Callvirt, propGetMethod);
il.Emit(OpCodes.Stloc, local0);
il.Emit(OpCodes.Ldloca_S, local0);
il.Emit(OpCodes.Call, toStringMethod);
il.Emit(OpCodes.Stloc, local1);
il.Emit(OpCodes.Br_S, label0);
il.MarkLabel(label0);
il.Emit(OpCodes.Ldloc, local1);
il.Emit(OpCodes.Ret);

return (Func<T, string>)dynamicMethod.CreateDelegate(typeof(Func<T, string>));

This version however is not optimized very much. It seems you took it from code that was compiled for debug mode.

The following version does the same, but more efficiently, mainly requiring no labels and only one local:

var propType = prop.PropertyType;
var propGetMethod = prop.GetMethod;

ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
LocalBuilder local0 = iLGenerator.DeclareLocal(propType);

iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Call, propGetMethod);
iLGenerator.Emit(OpCodes.Stloc, local0);
iLGenerator.Emit(OpCodes.Ldloca_S, local0);
iLGenerator.Emit(OpCodes.Call, toStringMethod);
iLGenerator.Emit(OpCodes.Ret);
return (Func<T, string>)dynamicMethod.CreateDelegate(typeof(Func<T, string>));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM