Emit动态生成代理类用于监控对象的字段修改

利用Emit动态生成代理对象监控对象哪些字段被修改,被修改为什么值

被Register的对象要监控的值必须是Virtual虚类型

必须使用CreateInstance创建对象

必须使用DynamicProxyGenerator.GetChangeProperties 获取改变的值

调用GetChangeProperties 返回的Dictionary.Clear() 重置当前已修改属性

对象赋值时增加变动修改,如果value 和原始值相同则不记录变动

支持注册多个对象到一个代理程序集

核心部分摘自 https://blog.csdn.net/lishuangquan1987/article/details/84312514

 

测试代码

 

using System;
using System.Diagnostics;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            DynamicProxyGenerator dpg = new DynamicProxyGenerator("DynamicAssembly");
            //注册类型
            dpg.Register<Person>();
            dpg.Register<Person2>();
            //保存为dll
            dpg.Save();
            Person p = dpg.CreateInstance<Person>();
            p.Name = "tom";
            p.Age = 12345;
            var changes = DynamicProxyGenerator.GetChangeProperties(p);
            Console.WriteLine($"第一次检测改变了{changes.Count}个属性");
            changes.Clear();
            p.Name = "tony";
            p.Age = 12345;
            changes = DynamicProxyGenerator.GetChangeProperties(p);
            Console.WriteLine($"第二次检测改变了{changes.Count}个属性");
            //创建对象测试
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < 100000; i++)
            {
                var p2 = dpg.CreateInstance<Person2>();
            }
            stopwatch.Stop();
            Console.WriteLine($"创建对象100000个用时{stopwatch.ElapsedMilliseconds}ms");
            Console.ReadKey();
        }
    }

    public class Person
    {
        public virtual String Name { get; set; }
        public virtual Int32 Age { get; set; }
    }
    public class Person2
    {
        public virtual String Name { get; set; }
        public virtual Int32 Age { get; set; }
    }
}

```



 

核心代码

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

namespace TestApp
{
    /// <summary>
    /// 动态代理类生成器
    /// </summary>
    public class DynamicProxyGenerator
    {
        private const string ModifiedPropertyNamesFieldName = "ChangePropertys";

        private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig;
        /// <summary>
        /// 程序集名称
        /// </summary>
        private AssemblyName assemblyName { get; set; }
        /// <summary>
        /// 程序集构建器
        /// </summary>
        private AssemblyBuilder assemblyBuilder { get; set; }

        /// <summary>
        /// 程序集模块
        /// </summary>
        private ModuleBuilder moduleBuilder { get; set; }

        /// <summary>
        /// 保存修改属性的集合类型
        /// </summary>
        private Type modifiedPropertyNamesType { get; set; }

        /// <summary>
        /// 构造一个动态代理生成器
        /// </summary>
        /// <param name="AssemblyName"></param>
        /// <param name="isSaveDynamicModule"></param>
        public DynamicProxyGenerator(String DynamicAssemblyName)
        {
            //创建程序集
            assemblyName = new AssemblyName(DynamicAssemblyName);
            assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            //动态创建模块
            moduleBuilder = assemblyBuilder.DefineDynamicModule(String.Format("{0}Module", DynamicAssemblyName), String.Format("{0}.dll", DynamicAssemblyName));
            //修改的属性集合类型
            modifiedPropertyNamesType = typeof(Dictionary<String, Object>);
        }

        /// <summary>
        /// 注册类型到代理生成器(只注册Virtual属性)
        /// </summary>
        /// <typeparam name="T">类</typeparam>
        /// <returns></returns>
        public void Register<T>()
        {
            Type typeNeedProxy = typeof(T);

            //创建动态类代理,这里名字不变 继承自T
            TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(typeNeedProxy.Name, TypeAttributes.Public, typeNeedProxy);
            //定义一个Dictionary变量存放属性变更名
            FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);

            /*
             * 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码
               ModifiedPropertyNames = new List<string>();
            */
            ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
            ILGenerator ilgCtor = constructorBuilder.GetILGenerator();
            ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类
            ilgCtor.Emit(OpCodes.Newobj, modifiedPropertyNamesType.GetConstructor(new Type[0]));//实例化对象入栈
            ilgCtor.Emit(OpCodes.Stfld, fbModifiedPropertyNames);//设置fbModifiedPropertyNames值,为刚入栈的实例化对象
            ilgCtor.Emit(OpCodes.Ret);//返回

            //获取被代理对象的所有属性,循环属性进行重写
            PropertyInfo[] properties = typeNeedProxy.GetProperties();
            foreach (PropertyInfo propertyInfo in properties)
            {
                string propertyName = propertyInfo.Name;
                Type typePepropertyInfo = propertyInfo.PropertyType;
                //动态创建字段和属性
                FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_" + propertyName.ToLower(), typePepropertyInfo, FieldAttributes.Private);
                PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.SpecialName, typePepropertyInfo, null);
                //重写属性的Get Set方法
                var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
                var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });
                //il of get method
                var ilGetMethod = methodGet.GetILGenerator();
                ilGetMethod.Emit(OpCodes.Ldarg_0);
                ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
                ilGetMethod.Emit(OpCodes.Ret);
                //il of set method
                ILGenerator ilSetMethod = methodSet.GetILGenerator();
                //声明布尔类型
                ilSetMethod.DeclareLocal(typeof(Boolean));
                //声明一个标签,标记到ret
                Label label = ilSetMethod.DefineLabel();
                //判断值是否改变
                ilSetMethod.Emit(OpCodes.Nop);
                ilSetMethod.Emit(OpCodes.Ldarg_0);
                ilSetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
                ilSetMethod.Emit(OpCodes.Ldarg_1);
                ilSetMethod.Emit(OpCodes.Ceq);
                ilSetMethod.Emit(OpCodes.Ldc_I4_0);
                ilSetMethod.Emit(OpCodes.Ceq);
                ilSetMethod.Emit(OpCodes.Stloc_0);
                ilSetMethod.Emit(OpCodes.Ldloc_0);
                //如果未改变,调到结束return
                ilSetMethod.Emit(OpCodes.Brfalse_S, label);
                //赋值
                ilSetMethod.Emit(OpCodes.Nop);
                ilSetMethod.Emit(OpCodes.Ldarg_0);
                ilSetMethod.Emit(OpCodes.Ldarg_1);
                ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
                //保存到 Dictionary
                ilSetMethod.Emit(OpCodes.Ldarg_0);
                ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
                ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
                ilSetMethod.Emit(OpCodes.Ldarg_1);
                ilSetMethod.Emit(OpCodes.Box, propertyInfo.PropertyType);
                ilSetMethod.Emit(OpCodes.Callvirt, modifiedPropertyNamesType.GetMethod("set_Item", new Type[] { typeof(string), typeof(Object) }));
                ilSetMethod.Emit(OpCodes.Nop);
                ilSetMethod.Emit(OpCodes.Nop);
                ilSetMethod.MarkLabel(label);
                ilSetMethod.Emit(OpCodes.Ret);
                //设置属性的Get Set方法
                propertyBuilder.SetGetMethod(methodGet);
                propertyBuilder.SetSetMethod(methodSet);
            }
            //引用下, 要不无法生成
            Type proxyClassType = typeBuilderProxy.CreateType();
        }

        /// <summary>
        /// 保存程序集到dll文件
        /// </summary>
        public void Save()
        {
            assemblyBuilder.Save($"{assemblyName.Name}.dll");
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T CreateInstance<T>()
        {
            Type typeNeedProxy = typeof(T);
            return (T)assemblyBuilder.CreateInstance(typeNeedProxy.Name);
        }

        /// <summary>
        /// 获取属性的变更名称,
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<String, Object> GetChangeProperties<T>(T obj)
        {
            FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName);
            if (fieldInfo == null) return null;
            object value = fieldInfo.GetValue(obj);
            return value as Dictionary<String, Object>;
        }
    }
}

```



 

 

 

来源:https://blog.csdn.net/Vblegend_2013/article/details/85228041

posted on 2018-12-28 21:29  夜里码码  阅读(186)  评论(0编辑  收藏  举报

导航