| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Linq;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Text;
- using System.Threading;
-
- namespace EmitCreateDynamicProxy
- {
- public class DynamicProxyGenerator
- {
-
- private const string DynamicAssemblyName = "DynamicAssembly";//动态程序集名称
- private const string DynamicModuleName = "DynamicAssemblyModule";
- private const string DynamicModuleDllName = "DynamicAssembly.dll";//动态模块名称
- private const string ProxyClassNameFormater = "{0}Proxy";
- private const string ModifiedPropertyNamesFieldName = "ModifiedPropertyNames";
- private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig;
-
- /// <summary>
- /// 创建动态程序集,返回AssemblyBuilder
- /// </summary>
- /// <param name="isSavaDll"></param>
- /// <returns></returns>
- private static AssemblyBuilder DefineDynamicAssembly(bool isSavaDll = false)
- {
- //动态创建程序集
- AssemblyName DemoName = new AssemblyName(DynamicAssemblyName);
- AssemblyBuilderAccess assemblyBuilderAccess = isSavaDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run;
- AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, assemblyBuilderAccess);
- return dynamicAssembly;
- }
-
- /// <summary>
- /// 创建动态模块,返回ModuleBuilder
- /// </summary>
- /// <param name="isSavaDll"></param>
- /// <returns>ModuleBuilder</returns>
- private static ModuleBuilder DefineDynamicModule(AssemblyBuilder dynamicAssembly, bool isSavaDll = false)
- {
- ModuleBuilder moduleBuilder = null;
- //动态创建模块
- if (isSavaDll)
- moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName, DynamicModuleDllName);
- else
- moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName);
- return moduleBuilder;
- }
-
- /// <summary>
- /// 创建动态代理类,重写属性Get Set 方法,并监控属性的Set方法,把变更的属性名加入到list集合中,需要监控的属性必须是virtual
- /// 如果你想保存修改的属性名和属性值,修改Set方法的IL实现
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="isSavaDynamicModule"></param>
- /// <returns></returns>
- public static T CreateDynamicProxy<T>(bool isSavaDynamicModule = false)
- {
- Type modifiedPropertyNamesType = typeof(HashSet<string>);
-
- Type typeNeedProxy = typeof(T);
- AssemblyBuilder assemblyBuilder = DefineDynamicAssembly(isSavaDynamicModule);
- //动态创建模块
- ModuleBuilder moduleBuilder = DefineDynamicModule(assemblyBuilder, isSavaDynamicModule);
- string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name);
- //动态创建类代理
- TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy);
- //定义一个变量存放属性变更名
- FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);
- //定义接口
- var pt = typeof(PropertyChangedEventHandler);
- typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
- var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));
-
- //add field
- var eb = typeBuilderProxy.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
-
- var compareExchange = GetGenericMethod(typeof(Interlocked), "CompareExchange");// finds the correct method to call.
- // thanks to @marc, create the specific method with the correct type
- compareExchange = compareExchange.MakeGenericMethod(typeof(PropertyChangedEventHandler));
-
- //add methoed
- var mas = MethodAttributes.Public | MethodAttributes.HideBySig
- | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final;
- var mb = typeBuilderProxy.DefineMethod("add_PropertyChanged", mas, typeof(void), new Type[] { pt });
- mb.DefineParameter(0, ParameterAttributes.Retval, null);
- mb.DefineParameter(1, ParameterAttributes.In, "value");
- var il = mb.GetILGenerator();
- il.DeclareLocal(pt);
- il.DeclareLocal(pt);
- il.DeclareLocal(pt);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldfld, eb);
- il.Emit(OpCodes.Stloc_0);
- var lable = il.DefineLabel();
- il.MarkLabel(lable);
- il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Stloc_1);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) }));
- il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
- il.Emit(OpCodes.Stloc_2);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldflda, eb);
- il.Emit(OpCodes.Ldloc_2);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Call, compareExchange);
- il.Emit(OpCodes.Stloc_0);
- il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Bne_Un_S, lable);
- il.Emit(OpCodes.Ret);
-
- //remove event
- mb = typeBuilderProxy.DefineMethod("remove_PropertyChanged", mas, typeof(void), new Type[] { pt });
- mb.DefineParameter(0, ParameterAttributes.Retval, null);
- mb.DefineParameter(1, ParameterAttributes.In, "value");
-
- il = mb.GetILGenerator();
- il.DeclareLocal(pt);
- il.DeclareLocal(pt);
- il.DeclareLocal(pt);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldfld, eb);
- il.Emit(OpCodes.Stloc_0);
- lable = il.DefineLabel();
- il.MarkLabel(lable);
- il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Stloc_1);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Ldarg_1);
- il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) }));
- il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
- il.Emit(OpCodes.Stloc_2);
- il.Emit(OpCodes.Ldarg_0);
- il.Emit(OpCodes.Ldflda, eb);
- il.Emit(OpCodes.Ldloc_2);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Call, compareExchange);
- il.Emit(OpCodes.Stloc_0);
- il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Ldloc_1);
- il.Emit(OpCodes.Bne_Un_S, lable);
- il.Emit(OpCodes.Ret);
-
- /*
- * 构造函数 实例化 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, 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();
- var nullLabel = ilSetMethod.DefineLabel();
- ilSetMethod.Emit(OpCodes.Ldarg_0);
- ilSetMethod.Emit(OpCodes.Ldarg_1);
- ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
- ilSetMethod.Emit(OpCodes.Ldarg_0);
- ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
- ilSetMethod.Emit(OpCodes.Dup);
- ilSetMethod.Emit(OpCodes.Brtrue_S, nullLabel);
- ilSetMethod.Emit(OpCodes.Pop);
- var retLabel = ilSetMethod.DefineLabel();
- ilSetMethod.Emit(OpCodes.Br_S, retLabel);
- ilSetMethod.MarkLabel(nullLabel);
- ilSetMethod.Emit(OpCodes.Ldarg_0);
- ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
- ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs));
- ilSetMethod.Emit(OpCodes.Callvirt, pt.GetMethod("Invoke", new Type[] { typeof(object), typeof(PropertyChangedEventArgs) }));
- ilSetMethod.Emit(OpCodes.Nop);
- il.MarkLabel(retLabel);
- ilSetMethod.Emit(OpCodes.Ret);
-
- //设置属性的Get Set方法
- propertyBuilder.SetGetMethod(methodGet);
- propertyBuilder.SetSetMethod(methodSet);
- }
-
- //使用动态类创建类型
- Type proxyClassType = typeBuilderProxy.CreateType();
- //保存动态创建的程序集
- if (isSavaDynamicModule)
- assemblyBuilder.Save(DynamicModuleDllName);
- //创建类实例
- var instance = Activator.CreateInstance(proxyClassType);
- return (T)instance;
- }
-
- /// <summary>
- /// 获取属性的变更名称,
- /// 此处只检测调用了Set方法的属性,不会检测值是否真的有变
- /// </summary>
- /// <param name="obj"></param>
- /// <returns></returns>
- public static HashSet<string> GetModifiedProperties(object obj)
- {
- FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName);
- if (fieldInfo == null) return null;
- object value = fieldInfo.GetValue(obj);
- return value as HashSet<string>;
- }
-
- private static MethodInfo GetGenericMethod(Type type, string methodName)
- {
- var q = from m in type.GetMethods()
- where m.Name == methodName && m.IsGenericMethod
- select m;
- return q.FirstOrDefault();
- }
- }
- }
|