LearningEmit
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

DynamicProxyGenerator.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Text;
  8. using System.Threading;
  9. namespace EmitCreateDynamicProxy
  10. {
  11. public class DynamicProxyGenerator
  12. {
  13. private const string DynamicAssemblyName = "DynamicAssembly";//动态程序集名称
  14. private const string DynamicModuleName = "DynamicAssemblyModule";
  15. private const string DynamicModuleDllName = "DynamicAssembly.dll";//动态模块名称
  16. private const string ProxyClassNameFormater = "{0}Proxy";
  17. private const string ModifiedPropertyNamesFieldName = "ModifiedPropertyNames";
  18. private const MethodAttributes GetSetMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.CheckAccessOnOverride | MethodAttributes.Virtual | MethodAttributes.HideBySig;
  19. /// <summary>
  20. /// 创建动态程序集,返回AssemblyBuilder
  21. /// </summary>
  22. /// <param name="isSavaDll"></param>
  23. /// <returns></returns>
  24. private static AssemblyBuilder DefineDynamicAssembly(bool isSavaDll = false)
  25. {
  26. //动态创建程序集
  27. AssemblyName DemoName = new AssemblyName(DynamicAssemblyName);
  28. AssemblyBuilderAccess assemblyBuilderAccess = isSavaDll ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run;
  29. AssemblyBuilder dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(DemoName, assemblyBuilderAccess);
  30. return dynamicAssembly;
  31. }
  32. /// <summary>
  33. /// 创建动态模块,返回ModuleBuilder
  34. /// </summary>
  35. /// <param name="isSavaDll"></param>
  36. /// <returns>ModuleBuilder</returns>
  37. private static ModuleBuilder DefineDynamicModule(AssemblyBuilder dynamicAssembly, bool isSavaDll = false)
  38. {
  39. ModuleBuilder moduleBuilder = null;
  40. //动态创建模块
  41. if (isSavaDll)
  42. moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName, DynamicModuleDllName);
  43. else
  44. moduleBuilder = dynamicAssembly.DefineDynamicModule(DynamicModuleName);
  45. return moduleBuilder;
  46. }
  47. /// <summary>
  48. /// 创建动态代理类,重写属性Get Set 方法,并监控属性的Set方法,把变更的属性名加入到list集合中,需要监控的属性必须是virtual
  49. /// 如果你想保存修改的属性名和属性值,修改Set方法的IL实现
  50. /// </summary>
  51. /// <typeparam name="T"></typeparam>
  52. /// <param name="isSavaDynamicModule"></param>
  53. /// <returns></returns>
  54. public static T CreateDynamicProxy<T>(bool isSavaDynamicModule = false)
  55. {
  56. Type modifiedPropertyNamesType = typeof(HashSet<string>);
  57. Type typeNeedProxy = typeof(T);
  58. AssemblyBuilder assemblyBuilder = DefineDynamicAssembly(isSavaDynamicModule);
  59. //动态创建模块
  60. ModuleBuilder moduleBuilder = DefineDynamicModule(assemblyBuilder, isSavaDynamicModule);
  61. string proxyClassName = string.Format(ProxyClassNameFormater, typeNeedProxy.Name);
  62. //动态创建类代理
  63. TypeBuilder typeBuilderProxy = moduleBuilder.DefineType(proxyClassName, TypeAttributes.Public, typeNeedProxy);
  64. //定义一个变量存放属性变更名
  65. FieldBuilder fbModifiedPropertyNames = typeBuilderProxy.DefineField(ModifiedPropertyNamesFieldName, modifiedPropertyNamesType, FieldAttributes.Public);
  66. //定义接口
  67. var pt = typeof(PropertyChangedEventHandler);
  68. typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
  69. var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.None, typeof(PropertyChangedEventHandler));
  70. //add field
  71. var eb = typeBuilderProxy.DefineField("PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
  72. var compareExchange = GetGenericMethod(typeof(Interlocked), "CompareExchange");// finds the correct method to call.
  73. // thanks to @marc, create the specific method with the correct type
  74. compareExchange = compareExchange.MakeGenericMethod(typeof(PropertyChangedEventHandler));
  75. //add methoed
  76. var mas = MethodAttributes.Public | MethodAttributes.HideBySig
  77. | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final;
  78. var mb = typeBuilderProxy.DefineMethod("add_PropertyChanged", mas, typeof(void), new Type[] { pt });
  79. mb.DefineParameter(0, ParameterAttributes.Retval, null);
  80. mb.DefineParameter(1, ParameterAttributes.In, "value");
  81. var il = mb.GetILGenerator();
  82. il.DeclareLocal(pt);
  83. il.DeclareLocal(pt);
  84. il.DeclareLocal(pt);
  85. il.Emit(OpCodes.Ldarg_0);
  86. il.Emit(OpCodes.Ldfld, eb);
  87. il.Emit(OpCodes.Stloc_0);
  88. var lable = il.DefineLabel();
  89. il.MarkLabel(lable);
  90. il.Emit(OpCodes.Ldloc_0);
  91. il.Emit(OpCodes.Stloc_1);
  92. il.Emit(OpCodes.Ldloc_1);
  93. il.Emit(OpCodes.Ldarg_1);
  94. il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) }));
  95. il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
  96. il.Emit(OpCodes.Stloc_2);
  97. il.Emit(OpCodes.Ldarg_0);
  98. il.Emit(OpCodes.Ldflda, eb);
  99. il.Emit(OpCodes.Ldloc_2);
  100. il.Emit(OpCodes.Ldloc_1);
  101. il.Emit(OpCodes.Call, compareExchange);
  102. il.Emit(OpCodes.Stloc_0);
  103. il.Emit(OpCodes.Ldloc_0);
  104. il.Emit(OpCodes.Ldloc_1);
  105. il.Emit(OpCodes.Bne_Un_S, lable);
  106. il.Emit(OpCodes.Ret);
  107. //remove event
  108. mb = typeBuilderProxy.DefineMethod("remove_PropertyChanged", mas, typeof(void), new Type[] { pt });
  109. mb.DefineParameter(0, ParameterAttributes.Retval, null);
  110. mb.DefineParameter(1, ParameterAttributes.In, "value");
  111. il = mb.GetILGenerator();
  112. il.DeclareLocal(pt);
  113. il.DeclareLocal(pt);
  114. il.DeclareLocal(pt);
  115. il.Emit(OpCodes.Ldarg_0);
  116. il.Emit(OpCodes.Ldfld, eb);
  117. il.Emit(OpCodes.Stloc_0);
  118. lable = il.DefineLabel();
  119. il.MarkLabel(lable);
  120. il.Emit(OpCodes.Ldloc_0);
  121. il.Emit(OpCodes.Stloc_1);
  122. il.Emit(OpCodes.Ldloc_1);
  123. il.Emit(OpCodes.Ldarg_1);
  124. il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) }));
  125. il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
  126. il.Emit(OpCodes.Stloc_2);
  127. il.Emit(OpCodes.Ldarg_0);
  128. il.Emit(OpCodes.Ldflda, eb);
  129. il.Emit(OpCodes.Ldloc_2);
  130. il.Emit(OpCodes.Ldloc_1);
  131. il.Emit(OpCodes.Call, compareExchange);
  132. il.Emit(OpCodes.Stloc_0);
  133. il.Emit(OpCodes.Ldloc_0);
  134. il.Emit(OpCodes.Ldloc_1);
  135. il.Emit(OpCodes.Bne_Un_S, lable);
  136. il.Emit(OpCodes.Ret);
  137. /*
  138. * 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码
  139. ModifiedPropertyNames = new List<string>();
  140. */
  141. ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
  142. ILGenerator ilgCtor = constructorBuilder.GetILGenerator();
  143. ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类
  144. ilgCtor.Emit(OpCodes.Newobj, modifiedPropertyNamesType.GetConstructor(new Type[0]));//实例化对象入栈
  145. ilgCtor.Emit(OpCodes.Stfld, fbModifiedPropertyNames);//设置fbModifiedPropertyNames值,为刚入栈的实例化对象
  146. ilgCtor.Emit(OpCodes.Ret);//返回
  147. //获取被代理对象的所有属性,循环属性进行重写
  148. PropertyInfo[] properties = typeNeedProxy.GetProperties();
  149. foreach (PropertyInfo propertyInfo in properties)
  150. {
  151. string propertyName = propertyInfo.Name;
  152. Type typePepropertyInfo = propertyInfo.PropertyType;
  153. //动态创建字段和属性
  154. FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_" + propertyName, typePepropertyInfo, FieldAttributes.Private);
  155. PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.SpecialName, typePepropertyInfo, null);
  156. //重写属性的Get Set方法
  157. var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
  158. var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, null, new Type[] { typePepropertyInfo });
  159. //il of get method
  160. var ilGetMethod = methodGet.GetILGenerator();
  161. ilGetMethod.Emit(OpCodes.Ldarg_0);
  162. ilGetMethod.Emit(OpCodes.Ldfld, fieldBuilder);
  163. ilGetMethod.Emit(OpCodes.Ret);
  164. //il of set method
  165. ILGenerator ilSetMethod = methodSet.GetILGenerator();
  166. var nullLabel = ilSetMethod.DefineLabel();
  167. ilSetMethod.Emit(OpCodes.Ldarg_0);
  168. ilSetMethod.Emit(OpCodes.Ldarg_1);
  169. ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
  170. ilSetMethod.Emit(OpCodes.Ldarg_0);
  171. ilSetMethod.Emit(OpCodes.Ldfld, fbModifiedPropertyNames);
  172. ilSetMethod.Emit(OpCodes.Dup);
  173. ilSetMethod.Emit(OpCodes.Brtrue_S, nullLabel);
  174. ilSetMethod.Emit(OpCodes.Pop);
  175. var retLabel = ilSetMethod.DefineLabel();
  176. ilSetMethod.Emit(OpCodes.Br_S, retLabel);
  177. ilSetMethod.MarkLabel(nullLabel);
  178. ilSetMethod.Emit(OpCodes.Ldarg_0);
  179. ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
  180. ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs));
  181. ilSetMethod.Emit(OpCodes.Callvirt, pt.GetMethod("Invoke", new Type[] { typeof(object), typeof(PropertyChangedEventArgs) }));
  182. ilSetMethod.Emit(OpCodes.Nop);
  183. il.MarkLabel(retLabel);
  184. ilSetMethod.Emit(OpCodes.Ret);
  185. //设置属性的Get Set方法
  186. propertyBuilder.SetGetMethod(methodGet);
  187. propertyBuilder.SetSetMethod(methodSet);
  188. }
  189. //使用动态类创建类型
  190. Type proxyClassType = typeBuilderProxy.CreateType();
  191. //保存动态创建的程序集
  192. if (isSavaDynamicModule)
  193. assemblyBuilder.Save(DynamicModuleDllName);
  194. //创建类实例
  195. var instance = Activator.CreateInstance(proxyClassType);
  196. return (T)instance;
  197. }
  198. /// <summary>
  199. /// 获取属性的变更名称,
  200. /// 此处只检测调用了Set方法的属性,不会检测值是否真的有变
  201. /// </summary>
  202. /// <param name="obj"></param>
  203. /// <returns></returns>
  204. public static HashSet<string> GetModifiedProperties(object obj)
  205. {
  206. FieldInfo fieldInfo = obj.GetType().GetField(ModifiedPropertyNamesFieldName);
  207. if (fieldInfo == null) return null;
  208. object value = fieldInfo.GetValue(obj);
  209. return value as HashSet<string>;
  210. }
  211. private static MethodInfo GetGenericMethod(Type type, string methodName)
  212. {
  213. var q = from m in type.GetMethods()
  214. where m.Name == methodName && m.IsGenericMethod
  215. select m;
  216. return q.FirstOrDefault();
  217. }
  218. }
  219. }