IL Emit - 重定向属性

时间:2016-11-03 15:27:06

标签: c# emit

我试图创建一个动态包装器,但可以解决我的错误。 这是我得到的:

简单数据类:

public class Data
{
    public int MyProperty { get; set; } = 42;
}

基类,提供重定向字段:

    public class WrapperBase<T> where T : new()
    {
        public WrapperBase()
        {
            Field = new T();
        }
        public T Field { get; set; }
        public void Foo();
    }

使用重定向基类的类:

public class SomeDynamicClass : WrapperBase<Data> { }

和使用它的课程:

public class User
{
    public User()
    {
        Content = MyFactory.Create<SomeDynamicClass>();
    }
    public object Content { get; set; }
}

这是我希望工厂创建的:

public class DesiredResult : SomeDynamicClass
{
    public int MyProperty
    {
        get { return Field.MyProperty; }
        set
        {
            Field.MyProperty = value;
            Foo();
        }
    }
}

我检查了IL代码并尝试重新编码,但是有一个我找不到的错误。这是我到目前为止所得到的:

public class Factory
{
    private const String NAMESPACE = "vmproxy.{0}";
    public object Create<T>() where T : class
    {
        AssemblyName an = new AssemblyName();
        an.Name = Guid.NewGuid().ToString();
        AppDomain ad = AppDomain.CurrentDomain;
        AssemblyBuilder ab = ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);

        var _mb = ab.DefineDynamicModule(an.Name);
        var fieldProp = typeof(T).GetProperty("Field");
        var modelType = typeof(T).GetProperty("Field").PropertyType;
        var name = typeof(T).Name;
        var tb = _mb.DefineType(String.Format(NAMESPACE, name), TypeAttributes.Public | TypeAttributes.Class, typeof(T));


        foreach (var property in modelType.GetProperties())
        {
            PropertyBuilder prop = tb.DefineProperty(property.Name, PropertyAttributes.None, property.PropertyType, null);
            MethodBuilder meth = tb.DefineMethod("get_" + property.Name,
                                                        MethodAttributes.Public |
                                                        MethodAttributes.SpecialName |
                                                        MethodAttributes.Virtual |
                                                        MethodAttributes.HideBySig,
                                                        property.PropertyType, Type.EmptyTypes);
            ILGenerator ilGen = meth.GetILGenerator();
            Label endOfMethod = ilGen.DefineLabel();
            ilGen.Emit(OpCodes.Ldarg_0);
            //ilGen.Emit(OpCodes.Call, fieldProp.GetGetMethod());
            ilGen.EmitCall(OpCodes.Call, fieldProp.GetGetMethod(), null);
            //ilGen.Emit(OpCodes.Callvirt, property.GetGetMethod());
            ilGen.EmitCall(OpCodes.Callvirt, property.GetGetMethod(),null);
            ilGen.Emit(OpCodes.Stloc_0);
            ilGen.Emit(OpCodes.Br_S, endOfMethod);
            ilGen.MarkLabel(endOfMethod);
            ilGen.Emit(OpCodes.Ldloc_0);
            ilGen.Emit(OpCodes.Ret);
            prop.SetGetMethod(meth);

            //meth = tb.DefineMethod("set_" + property.Name,
            //                                MethodAttributes.Public |
            //                                MethodAttributes.SpecialName |
            //                                MethodAttributes.Virtual |
            //                                MethodAttributes.HideBySig,
            //                                null, new Type[] { property.PropertyType });
            //ilGen = meth.GetILGenerator();
            //ilGen.Emit(OpCodes.Ldarg_0);
            //TBD...
            break;
        }

        return Activator.CreateInstance(tb.CreateType());
    }

好像我正在生成无效的IL代码......有没有办法检查创建的IL代码?...

编辑:我正在尝试创建的IL代码:

    .method public hidebysig specialname instance int32 
            get_IntProp() cil managed
    {
      // Code size       17 (0x11)
      .maxstack  1
      .locals init ([0] int32 V_0)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  call       instance !0 class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data>::get_Field()
      IL_0007:  callvirt   instance int32 FactoryWrapper.Data::get_IntProp()
      IL_000c:  stloc.0
      IL_000d:  br.s       IL_000f
      IL_000f:  ldloc.0
      IL_0010:  ret
    } // end of method DerivedClass3::get_IntProp



.method public hidebysig specialname instance void 
        set_IntProp(int32 'value') cil managed
{
  // Code size       27 (0x1b)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       instance !0 class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data1::get_Field()
  IL_0007:  ldarg.1
  IL_0008:  callvirt   instance void FactoryWrapper.Data::set_IntProp(int32)
  IL_000d:  nop
  IL_000e:  ldarg.0
  IL_0014:  callvirt   instance void class FactoryWrapper.WrapperBase`1<class FactoryWrapper.Data1>::Foo()
  IL_0019:  nop
  IL_001a:  ret
} // end of method DerivedClass3::set_IntProp

编辑:接收&#34; 偏移0x000c处的未知本地变量数&#34;

1 个答案:

答案 0 :(得分:1)

一旦我明白了,答案很简单:

        ILGenerator ilGen = meth.GetILGenerator();

        ilGen.Emit(OpCodes.Ldarg_0);
        ilGen.EmitCall(OpCodes.Call, fieldProp.GetGetMethod(), null);
        ilGen.EmitCall(OpCodes.Callvirt, property.GetGetMethod(), null);
        ilGen.Emit(OpCodes.Ret);

        prop.SetGetMethod(meth);

我在ILDASM中使用的代码包含许多堆栈操作的方法,这些操作不是必需的,甚至是错误的。不知道为什么这个代码甚至可以工作......我发布的内容就像一个魅力。