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);
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",
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",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,null);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder getAccessor = tb.DefineMethod(string.Format("get_{0}",getSetAttr,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}",new Type[] { type });
setAccessor.DefineParameter(1,"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");
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。