IL Emit - 重定向 属性
IL Emit - redirecting a property
我正在尝试创建一个动态包装器,但可以避免我的错误。
这是我得到的:
简单数据class:
public class Data
{
public int MyProperty { get; set; } = 42;
}
A Base class,提供重定向字段:
public class WrapperBase<T> where T : new()
{
public WrapperBase()
{
Field = new T();
}
public T Field { get; set; }
public void Foo();
}
A class 使用重定向基础:
public class SomeDynamicClass : WrapperBase<Data> { }
和 class 使用它:
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
编辑:接收“未知局部变量号在偏移量 0x000c”
一旦我有了想法,答案就很简单了:
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 使用的代码包含许多堆栈操作的方式,这些操作不是必需的,而且似乎是错误的。不知道为什么该代码甚至可以工作...我发布的内容很有魅力。
我正在尝试创建一个动态包装器,但可以避免我的错误。 这是我得到的:
简单数据class:
public class Data
{
public int MyProperty { get; set; } = 42;
}
A Base class,提供重定向字段:
public class WrapperBase<T> where T : new() { public WrapperBase() { Field = new T(); } public T Field { get; set; } public void Foo(); }
A class 使用重定向基础:
public class SomeDynamicClass : WrapperBase<Data> { }
和 class 使用它:
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
编辑:接收“未知局部变量号在偏移量 0x000c”
一旦我有了想法,答案就很简单了:
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 使用的代码包含许多堆栈操作的方式,这些操作不是必需的,而且似乎是错误的。不知道为什么该代码甚至可以工作...我发布的内容很有魅力。