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

本文介绍了一种利用代理模式实现属性变化监听的方法,通过在代理类中维护一个字典来跟踪属性更改,实现了对属性变化的高效检测与记录。同时,通过反编译生成的代理类代码,展示了具体的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一篇:https://blog.youkuaiyun.com/Vblegend_2013/article/details/85228041

本章

_changepropertys 设为私有对象

构建代理对象时继承了IPropertyChanged,实现了两个方法 保证了效率问题

获取更新记录数

获取更新字段信息

    public interface IPropertyChanged
    {
        Int32 GetChangedCount();
        IEnumerable<KeyValuePair<String, Object>> GetAndResetChanges();
    }

 

反编译后的生成代理类

using System;
using System.Collections.Generic;
using System.Linq;
using WindowsFormsApp1;

public class Person : WindowsFormsApp1.Person, IPropertyChanged
{
	private Dictionary<string, object> ChangePropertys = new Dictionary<string, object>();

	private string _name;

	private int _age;

	public override string Name
	{
		get
		{
			return this._name;
		}
		set
		{
			bool flag = this._name != value;
			if (flag)
			{
				this._name = value;
				this.ChangePropertys["Name"] = value;
			}
		}
	}

	public override int Age
	{
		get
		{
			return this._age;
		}
		set
		{
			bool flag = this._age != value;
			if (flag)
			{
				this._age = value;
				this.ChangePropertys["Age"] = value;
			}
		}
	}

	public override IEnumerable<KeyValuePair<string, object>> GetAndResetChanges()
	{
		KeyValuePair<string, object>[] result = this.ChangePropertys.ToArray<KeyValuePair<string, object>>();
		this.ChangePropertys.Clear();
		return result;
	}

	public override int GetChangedCount()
	{
		return this.ChangePropertys.Count;
	}
}

 

 

 

测试代码

using System;
using System.Diagnostics;
using System.Linq;

namespace WindowsFormsApp1
{
    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;
            Console.WriteLine($"第一次检测改变了{DynamicProxyGenerator.GetChangedCount(p)}");
            var changes = DynamicProxyGenerator.GetAndResetChanges(p);
            Console.WriteLine($"第一次检测改变了{changes.Count()}个属性");

            p.Name = "tony";
            p.Age = 12345;
            Console.WriteLine($"第二次检测改变了{DynamicProxyGenerator.GetChangedCount(p)}");
            changes = DynamicProxyGenerator.GetAndResetChanges(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 WindowsFormsApp1
{
    /// <summary>
    /// 属性改变接口
    /// </summary>
    public interface IPropertyChanged
    {
        Int32 GetChangedCount();
        IEnumerable<KeyValuePair<String, Object>> GetAndResetChanges();
    }

    /// <summary>
    /// 动态代理类生成器
    /// </summary>
    public class DynamicProxyGenerator
    {
        /// <summary>
        /// 改变属性数据集
        /// </summary>
        private const string ModifiedPropertyNamesFieldName = "_changepropertys";
        /// <summary>
        /// 重写方法属性
        /// </summary>
        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, new Type[] { typeof(IPropertyChanged) });
            //定义一个Dictionary变量存放属性变更名
            FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Private);
            /*
             * 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码
               ModifiedPropertyNames = new List<string>();
            */
            #region constructor
            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);//返回
            #endregion

            #region interface 
            #region GetAndResetChanges
            var getandreset = typeBuilderProxy.DefineMethod("GetAndResetChanges", GetSetMethodAttributes, typeof(IEnumerable<KeyValuePair<String, Object>>), Type.EmptyTypes);
            ILGenerator ilgetreset = getandreset.GetILGenerator();
            ilgetreset.DeclareLocal(typeof(KeyValuePair<String, Object>[]));
            ilgetreset.DeclareLocal(typeof(IEnumerable<KeyValuePair<String, Object>>));
            //声明一个标签,标记到ret
            Label lab1d = ilgetreset.DefineLabel();
            ilgetreset.Emit(OpCodes.Nop);
            ilgetreset.Emit(OpCodes.Ldarg_0);
            ilgetreset.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
            var toarray = typeof(System.Linq.Enumerable).GetMethod("ToArray");
            toarray = toarray.MakeGenericMethod(typeof(KeyValuePair<String, Object>));
            ilgetreset.Emit(OpCodes.Call, toarray);
            ilgetreset.Emit(OpCodes.Stloc_0);
            ilgetreset.Emit(OpCodes.Ldarg_0);
            ilgetreset.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
            ilgetreset.Emit(OpCodes.Callvirt, modifiedPropertyNamesType.GetMethod("Clear", new Type[0]));
            ilgetreset.Emit(OpCodes.Nop);
            ilgetreset.Emit(OpCodes.Ldloc_0);
            ilgetreset.Emit(OpCodes.Stloc_1);
            ilgetreset.Emit(OpCodes.Br_S, lab1d);
            ilgetreset.MarkLabel(lab1d);
            ilgetreset.Emit(OpCodes.Ldloc_1);
            ilgetreset.Emit(OpCodes.Ret);
            #endregion

            #region GetChangedCount
            var getchangedcount = typeBuilderProxy.DefineMethod("GetChangedCount", GetSetMethodAttributes, typeof(Int32), Type.EmptyTypes);
            ILGenerator ilgetcount = getchangedcount.GetILGenerator();
            ilgetcount.DeclareLocal(typeof(Int32));
            //声明一个标签,标记到ret
            Label lab0f = ilgetcount.DefineLabel();
            ilgetcount.Emit(OpCodes.Nop);
            ilgetcount.Emit(OpCodes.Ldarg_0);
            ilgetcount.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
            ilgetcount.Emit(OpCodes.Callvirt, modifiedPropertyNamesType.GetMethod("get_Count", new Type[0]));
            ilgetcount.Emit(OpCodes.Stloc_0);
            ilgetcount.Emit(OpCodes.Br_S, lab0f);
            ilgetcount.MarkLabel(lab0f);
            ilgetcount.Emit(OpCodes.Ldloc_0);
            ilgetcount.Emit(OpCodes.Ret);
            #endregion
            #endregion

            #region Build Proxy Property
            //获取被代理对象的所有属性,循环属性进行重写
            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方法

                #region Method Get
                //il of get method
                var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
                var ilGetMethod = methodGet.GetILGenerator();
                ilGetMethod.Emit(OpCodes.Ldarg_0);
                ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
                ilGetMethod.Emit(OpCodes.Ret);
                #endregion

                #region Method Set
                var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });
                //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方法
                #endregion

                propertyBuilder.SetGetMethod(methodGet);
                propertyBuilder.SetSetMethod(methodSet);
            }
            #endregion

            //引用下, 要不无法生成
            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 IEnumerable<KeyValuePair<String, Object>> GetAndResetChanges<T>(T obj)
        {
            var instance = obj as IPropertyChanged;
            if (instance == null)
            {
                throw new ArgumentException("obj IPropertyChanged");
            }
            return instance.GetAndResetChanges();
        }

        /// <summary>
        /// 获取改变记录数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Int32 GetChangedCount<T>(T obj) 
        {
            var instance = obj as IPropertyChanged;
            if (instance == null)
            {
                throw new ArgumentException("obj IPropertyChanged");
            }
            return instance.GetChangedCount();
        }

        /// <summary>
        /// 转换为IPropertyChanged;
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public IPropertyChanged ByPropertyChanged<T>(T obj)
        {
            return obj as IPropertyChanged;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值