用于创建实现 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");

    }

}

 http://blog.csdn.net/websco/archive/2010/03/10/5363572.aspx

posted @ 2010-03-27 10:08  周宏伟  阅读(676)  评论(0编辑  收藏  举报