如何发射新结构

时间:2017-06-07 08:35:39

标签: c# .net cil

var instanceType = typeof(T);            
LocalBuilder instanceBuilder = il.DeclareLocal(instanceType);// T 
if (instanceType.IsValueType)
{
    il.Emit(OpCodes.Ldloca, instanceBuilder);
    il.Emit(OpCodes.Initobj, instanceBuilder);
    il.Emit(OpCodes.Stloc_S, instanceBuilder);
}
else
{
    il.Emit(OpCodes.Newobj, instanceType.GetConstructor(Type.EmptyTypes));
    il.Emit(OpCodes.Stloc_S, instanceBuilder);
}

il.Emit(OpCodes.Ldstr, "Test");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { TypeUtil._StringType }));

il.Emit(OpCodes.Ldloc, instanceBuilder);
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { TypeUtil._ObjectType }));

有人能通过默认构造函数告诉我如何发布新的结构吗?

1 个答案:

答案 0 :(得分:0)

您需要的只是ldloca(或ldflda / ldsflda)和initobj。无需存储(stloc_s是不必要的)。 initobj的第二个参数是类型标记,而不是地址:

using System;
using System.Reflection.Emit;

static class Program
{
    static void Main()
    {

        var method = new DynamicMethod("create", typeof(Foo), new[] { typeof(int) });
        var il = method.GetILGenerator();
        var local = il.DeclareLocal(typeof(Foo));

        // initialize the local (essentially: the default ctor)
        il.Emit(OpCodes.Ldloca_S, local);
        il.Emit(OpCodes.Initobj, typeof(Foo));

        // assign the parameter value to the property
        il.Emit(OpCodes.Ldloca_S, local);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call,
            typeof(Foo).GetProperty(nameof(Foo.Id)).GetSetMethod());

        // load, box, and call CWL
        il.Emit(OpCodes.Ldloc_S, local);
        il.Emit(OpCodes.Box, typeof(Foo));
        il.Emit(OpCodes.Call, typeof(Console).GetMethod(
            nameof(Console.WriteLine), new[] { typeof(object) }));

        // return the value of the 
        il.Emit(OpCodes.Ldloc_S, local);
        il.Emit(OpCodes.Ret);

        // call the emitted method
        var del = (Func<int, Foo>)method.CreateDelegate(typeof(Func<int, Foo>));
        var foo = del(42);
    }

}
public struct Foo
{
    public int Id { get; set; } // not usually a good idea, note
    public override string ToString() => Id.ToString();
}