using System;
using System.Reflection;
using System.Reflection.Emit;
/// <summary>
/// 用于创建动态类型,并添加各个 public 属性的定义
/// </summary>
public class DynamicTypeBuilder
{
TypeBuilder tb;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="typeNm">动态类型的名称</param>
public DynamicTypeBuilder(string typeNm)
{
// 在 Silverlight 中 AssemblyBuilderAccess 没有 RunAndSave
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("TempAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder mb = ab.DefineDynamicModule("TempModule");
this.tb = mb.DefineType(typeNm, TypeAttributes.Public);
}
/// <summary>
/// 添加一个public的可读写属性,并且会创建对应的名为 propertyNm + "Field" 的私有字段
/// </summary>
/// <param name="propertyNm"></param>
/// <param name="type"></param>
public void AppendPublicProperty(string propertyNm, Type type)
{
this.AppendPublicProperty(propertyNm, type, true, true);
}
/// <summary>
/// 添加一个public属性,并且会创建对应的名为 propertyNm + "Field" 的私有字段
/// </summary>
/// <param name="propertyNm"></param>
/// <param name="type"></param>
/// <param name="canGet">是否实现getter</param>
/// <param name="canSet">是否实现setter</param>
public void AppendPublicProperty(string propertyNm, Type type, bool canGet, bool canSet)
{
FieldBuilder field = this.tb.DefineField(string.Format("{0}Field", propertyNm), type, FieldAttributes.Private);
PropertyBuilder property = tb.DefineProperty(propertyNm, PropertyAttributes.HasDefault, type, null);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
if (canGet)
{
MethodBuilder getAccessor = tb.DefineMethod(string.Format("get_{0}", propertyNm), getSetAttr, type, Type.EmptyTypes);
ILGenerator getIL = getAccessor.GetILGenerator();
#region 按照 IL 代码的写法
// 按照 IL 代码的写法,不能运行
//.method public hidebysig specialname instance int32
// get_A() cil managed
//{
// // Code size 12 (0xc)
// .maxstack 1
// .locals init ([0] int32 CS$1$0000)
// IL_0000: nop
// IL_0001: ldarg.0
// IL_0002: ldfld int32 WpfApplication2.Person::AField
// IL_0007: stloc.0
// IL_0008: br.s IL_000a
// IL_000a: ldloc.0
// IL_000b: ret
//} // end of method Person::get_A
// 按照上面 IL 代码的写法,不能运行 :
//Label getBrsLabel = getIL.DefineLabel();
//getIL.Emit(OpCodes.Nop);
//getIL.Emit(OpCodes.Ldarg_0);
//getIL.Emit(OpCodes.Ldfld, field);
//getIL.Emit(OpCodes.Stloc_0);
//getIL.Emit(OpCodes.Br_S, getBrsLabel);
//getIL.MarkLabel(getBrsLabel);
//getIL.Emit(OpCodes.Ldloc_0);
//getIL.Emit(OpCodes.Ret);
#endregion
// For an instance property, argument default is the instance. Load the
// instance, then load the private field and return, leaving the
// field value on the stack.
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, field);
getIL.Emit(OpCodes.Ret);
property.SetGetMethod(getAccessor);
}
if (canSet)
{
MethodBuilder setAccessor = tb.DefineMethod(string.Format("set_{0}", propertyNm), getSetAttr, null, new Type[] { type });
setAccessor.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator setIL = setAccessor.GetILGenerator();
// Load the instance and then the numeric argument, then store the
// argument in the field.
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, field);
setIL.Emit(OpCodes.Ret);
property.SetSetMethod(setAccessor);
}
}
/// <summary>
/// 在添加完各个 public 属性之后,调用此方法以完成对动态类型的定义并加载之,
/// 此后通过 Activator.CreateInstance() 便可实例化动态类型
/// </summary>
/// <returns></returns>
public Type CreateDynamicType()
{
return this.tb.CreateType();
}
}