用于创建实现 System.ComponentModel.INotifyPropertyChanged 接口的动态类型,并添加各个 public 属性的定义
using System.Reflection;
using System.Reflection.Emit;
/// <summary>
/// 用于创建实现 System.ComponentModel.INotifyPropertyChanged 接口的动态类型,并添加各个 public 属性的定义
/// </summary>
public class DynamicINotifyPropertyChangedTypeBuilder
{
/// <summary>
/// 用于在导出程序集至硬盘时使用(要求AssemblyBuilderAccess.RunAndSave),不过在 Silverlight 中不能使用
/// </summary>
AssemblyBuilder ab;
TypeBuilder tb;
/// <summary>
/// 用于在调用 RaisePropertyChanged() 时使用
/// </summary>
MethodBuilder raiseEventMB;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="typeNm">动态类型的名称</param>
public DynamicINotifyPropertyChangedTypeBuilder(string typeNm)
{
this.ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("TempAssembly"), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule("NotifyPropertyChangedObject", "TempAssembly.dll");
// Silverlight 或者不使用 AssemblyBuilderAccess.RunAndSave 的写法
//this.ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
// new AssemblyName("TempAssembly"), AssemblyBuilderAccess.Run);
//ModuleBuilder mb = ab.DefineDynamicModule("NotifyPropertyChangedObject");
this.tb = mb.DefineType(typeNm, TypeAttributes.Public | TypeAttributes.BeforeFieldInit);
this.ImplementationInterface();
}
/// <summary>
/// 用于生成实现 System.ComponentModel.INotifyPropertyChanged 的IL代码
/// </summary>
void ImplementationInterface()
{
// 实现接口
this.tb.AddInterfaceImplementation(typeof(System.ComponentModel.INotifyPropertyChanged));
// 事件类型
Type eventType = typeof(System.ComponentModel.PropertyChangedEventHandler);
// IL代码中生成了一个与事件同名的私有字段
FieldBuilder eventField = this.tb.DefineField("PropertyChanged", eventType, FieldAttributes.Private);
// 定义事件
EventBuilder eb = this.tb.DefineEvent("PropertyChanged", EventAttributes.None, eventType);
#region 生成 add_PropertyChanged 和 remove_PropertyChanged
// 注意add_PropertyChanged 和 remove_PropertyChanged 这两个事件要求 MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName | MethodAttributes.Virtual 等属性
MethodBuilder addEventMB = this.tb.DefineMethod("add_PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName | MethodAttributes.Virtual,
null, new Type[] { eventType });
//注意在使用事件时,使用的是+=操作,但在IL代码中应该使用Delegate.Combine方法
ILGenerator addEventIL = addEventMB.GetILGenerator();
addEventIL.Emit(OpCodes.Ldarg_0);
addEventIL.Emit(OpCodes.Ldarg_0);
addEventIL.Emit(OpCodes.Ldfld, eventField);
addEventIL.Emit(OpCodes.Ldarg_1);
addEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { eventType, eventType }));
//返回的是Delegate类型,所以需要进行转换
addEventIL.Emit(OpCodes.Castclass, eventType);
addEventIL.Emit(OpCodes.Stfld, eventField);
addEventIL.Emit(OpCodes.Ret);
eb.SetAddOnMethod(addEventMB);
MethodBuilder removeEventMB = this.tb.DefineMethod("remove_PropertyChanged",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName | MethodAttributes.Virtual,
null, new Type[] { eventType });
//注意在使用事件时,使用的是-=操作,但在IL代码中应该使用Delegate.Remove方法
ILGenerator removeEventIL = removeEventMB.GetILGenerator();
removeEventIL.Emit(OpCodes.Ldarg_0);
removeEventIL.Emit(OpCodes.Ldarg_0);
removeEventIL.Emit(OpCodes.Ldfld, eventField);
removeEventIL.Emit(OpCodes.Ldarg_1);
removeEventIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { eventType, eventType }));
removeEventIL.Emit(OpCodes.Castclass, eventType);
removeEventIL.Emit(OpCodes.Stfld, eventField);
removeEventIL.Emit(OpCodes.Ret);
eb.SetRemoveOnMethod(removeEventMB);
#endregion
#region 生成 RaisePropertyChanged
//要生成的代码原型(为了便于测试故意声明为 public):
//protected void RaisePropertyChanged(string propertyName)
//{
// PropertyChangedEventHandler temp = this.PropertyChanged;
// if (temp != null)
// {
// PropertyChangedEventArgs arg = new PropertyChangedEventArgs(propertyName);
// temp(this, arg);
// }
//}
// IL代码为:
//.method public hidebysig instance void NotifyPropertyChanged(string propertyName) cil managed
//{
// // Code size 35 (0x23)
// .maxstack 3
// .locals init ([0] class [System]System.ComponentModel.PropertyChangedEventHandler temp,
// [1] class [System]System.ComponentModel.PropertyChangedEventArgs arg,
// [2] bool CS$4$0000)
// IL_0000: nop
// IL_0001: ldarg.0
// IL_0002: ldfld class [System]System.ComponentModel.PropertyChangedEventHandler WpfApplication2.Person::PropertyChanged
// IL_0007: stloc.0
// IL_0008: ldloc.0
// IL_0009: ldnull
// IL_000a: ceq
// IL_000c: stloc.2
// IL_000d: ldloc.2
// IL_000e: brtrue.s IL_0022
// IL_0010: nop
// IL_0011: ldarg.1
// IL_0012: newobj instance void [System]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
// IL_0017: stloc.1
// IL_0018: ldloc.0
// IL_0019: ldarg.0
// IL_001a: ldloc.1
// IL_001b: callvirt instance void [System]System.ComponentModel.PropertyChangedEventHandler::Invoke(object,
// class [System]System.ComponentModel.PropertyChangedEventArgs)
// IL_0020: nop
// IL_0021: nop
// IL_0022: ret
//} // end of method Person::NotifyPropertyChanged
//下述的 ILGenerator 所生成的 IL 代码为:
//.method public hidebysig instance void RaisePropertyChanged(string propertyName) cil managed
//{
// // Code size 26 (0x1a)
// .maxstack 3
// .locals init (class [System]System.ComponentModel.PropertyChangedEventHandler V_0,
// class [System]System.ComponentModel.PropertyChangedEventArgs V_1)
// IL_0000: ldarg.0
// IL_0001: ldfld class [System]System.ComponentModel.PropertyChangedEventHandler LB::PropertyChanged
// IL_0006: stloc.0
// IL_0007: ldloc.0
// IL_0008: brfalse.s IL_0019
// IL_000a: ldarg.1
// IL_000b: newobj instance void [System]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
// IL_0010: stloc.1
// IL_0011: ldloc.0
// IL_0012: ldarg.0
// IL_0013: ldloc.1
// IL_0014: callvirt instance void [System]System.ComponentModel.PropertyChangedEventHandler::Invoke(object,
// class [System]System.ComponentModel.PropertyChangedEventArgs)
// IL_0019: ret
//} // end of method LB::RaisePropertyChanged
this.raiseEventMB = this.tb.DefineMethod("RaisePropertyChanged", MethodAttributes.Family | MethodAttributes.HideBySig, null, new Type[] { typeof(String) });
raiseEventMB.DefineParameter(1, ParameterAttributes.None, "propertyName");
ILGenerator raiseEventIL = raiseEventMB.GetILGenerator();
// 定义 temp 和 arg 两个临时变量
LocalBuilder temp = raiseEventIL.DeclareLocal(eventType);
LocalBuilder arg = raiseEventIL.DeclareLocal(typeof(System.ComponentModel.PropertyChangedEventArgs));
Label returnLabel = raiseEventIL.DefineLabel();
//System.ComponentModel.PropertyChangedEventHandler temp = this.PropertyChanged;
raiseEventIL.Emit(OpCodes.Ldarg_0);
raiseEventIL.Emit(OpCodes.Ldfld, eventField);
raiseEventIL.Emit(OpCodes.Stloc_0);
//if (temp == null) return
raiseEventIL.Emit(OpCodes.Ldloc_0);
raiseEventIL.Emit(OpCodes.Brfalse_S, returnLabel);
//System.ComponentModel.PropertyChangedEventArgs arg = new PropertyChangedEventArgs(propertyName);
raiseEventIL.Emit(OpCodes.Ldarg_1);
raiseEventIL.Emit(OpCodes.Newobj, typeof(System.ComponentModel.PropertyChangedEventArgs).GetConstructor(new Type[] { typeof(String) }));
raiseEventIL.Emit(OpCodes.Stloc_1);
//temp(this, arg);
raiseEventIL.Emit(OpCodes.Ldloc_0);
raiseEventIL.Emit(OpCodes.Ldarg_0);
raiseEventIL.Emit(OpCodes.Ldloc_1);
raiseEventIL.Emit(OpCodes.Callvirt, eventType.GetMethod("Invoke"));
raiseEventIL.MarkLabel(returnLabel);
raiseEventIL.Emit(OpCodes.Ret);
#endregion
#region 生成 RaisePropertyChanged
//要生成的代码原型(为了便于测试故意声明为 public):
//public void RaisePropertyChanged(string propertyName)
//{
// if (PropertyChanged != null)
// {
// PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
// }
//}
//IL代码为:
//.method public hidebysig instance void NotifyPropertyChanged(string propertyName) cil managed
//{
// // Code size 36 (0x24)
// .maxstack 4
// .locals init ([0] bool CS$4$0000)
// IL_0000: nop
// IL_0001: ldarg.0
// IL_0002: ldfld class [System]System.ComponentModel.PropertyChangedEventHandler WpfApplication2.Person::PropertyChanged
// IL_0007: ldnull
// IL_0008: ceq
// IL_000a: stloc.0
// IL_000b: ldloc.0
// IL_000c: brtrue.s IL_0023
// IL_000e: nop
// IL_000f: ldarg.0
// IL_0010: ldfld class [System]System.ComponentModel.PropertyChangedEventHandler WpfApplication2.Person::PropertyChanged
// IL_0015: ldarg.0
// IL_0016: ldarg.1
// IL_0017: newobj instance void [System]System.ComponentModel.PropertyChangedEventArgs::.ctor(string)
// IL_001c: callvirt instance void [System]System.ComponentModel.PropertyChangedEventHandler::Invoke(object,
// class [System]System.ComponentModel.PropertyChangedEventArgs)
// IL_0021: nop
// IL_0022: nop
// IL_0023: ret
//} // end of method Person::NotifyPropertyChanged
//this.raiseEventMB = this.tb.DefineMethod("RaisePropertyChanged", MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] { typeof(String) });
//raiseEventMB.DefineParameter(1, ParameterAttributes.None, "propertyName");
//ILGenerator raiseEventIL = raiseEventMB.GetILGenerator();
//Label returnLabel = raiseEventIL.DefineLabel();
// 完全按照上面 IL 代码的写法,不能运行
//raiseEventIL.Emit(OpCodes.Nop);
//raiseEventIL.Emit(OpCodes.Ldarg_0);
//raiseEventIL.Emit(OpCodes.Ldfld, eventField);
//raiseEventIL.Emit(OpCodes.Ldnull);
//raiseEventIL.Emit(OpCodes.Ceq);
//raiseEventIL.Emit(OpCodes.Stloc_0);
//raiseEventIL.Emit(OpCodes.Ldloc_0);
//raiseEventIL.Emit(OpCodes.Brtrue_S , returnLabel );
//raiseEventIL.Emit(OpCodes.Nop);
//raiseEventIL.Emit(OpCodes.Ldarg_0);
//raiseEventIL.Emit(OpCodes.Ldfld, eventField);
//raiseEventIL.Emit(OpCodes.Ldarg_0);
//raiseEventIL.Emit(OpCodes.Ldarg_1);
//raiseEventIL.Emit(OpCodes.Newobj, typeof(System.ComponentModel.PropertyChangedEventArgs).GetConstructor(new Type[] { typeof(String) }));
//raiseEventIL.Emit(OpCodes.Callvirt, eventType.GetMethod("Invoke"));
//raiseEventIL.Emit(OpCodes.Nop);
//raiseEventIL.Emit(OpCodes.Nop);
//raiseEventIL.MarkLabel(returnLabel);
//raiseEventIL.Emit(OpCodes.Ret);
#endregion
}
/// <summary>
/// 添加一个public的可读写属性,并且会创建对应的名为 propertyNm + "Field" 的私有字段。
/// 对于 setter 则会引发 PropertyChanged 事件
/// </summary>
/// <param name="propertyNm"></param>
/// <param name="type"></param>
public void AppendPublicPropertyByRaisingPropertyChanging(string propertyNm, Type type)
{
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;
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);
MethodBuilder setAccessor = tb.DefineMethod(string.Format("set_{0}", propertyNm), getSetAttr, null, new Type[] { type });
setAccessor.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator setIL = setAccessor.GetILGenerator();
setIL.Emit(OpCodes.Nop);
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, field);
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldstr, propertyNm);
setIL.Emit(OpCodes.Call, this.raiseEventMB);
setIL.Emit(OpCodes.Nop);
setIL.Emit(OpCodes.Ret);
property.SetSetMethod(setAccessor);
}
/// <summary>
/// 在添加完各个 public 属性之后,调用此方法以完成对动态类型的定义并加载之,
/// 此后通过 Activator.CreateInstance() 便可实例化动态类型
/// </summary>
/// <returns></returns>
public Type CreateDynamicType()
{
return this.tb.CreateType();
}
/// <summary>
/// 保存程序集至硬盘,Silverlight 中无此功能
/// </summary>
public void Save()
{
this.ab.Save("TempAssembly.dll");
}
}