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();
}
}