LearningEmit
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

DynamicProxyGenerator.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. * 构造函数 实例化 ModifiedPropertyNames,生成类似于下面的代码
  66. ModifiedPropertyNames = new List<string>();
  67. */
  68. ConstructorBuilder constructorBuilder = typeBuilderProxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
  69. ILGenerator ilgCtor = constructorBuilder.GetILGenerator();
  70. ilgCtor.Emit(OpCodes.Ldarg_0);//加载当前类
  71. ilgCtor.Emit(OpCodes.Call, typeNeedProxy.GetConstructor(Type.EmptyTypes));
  72. ilgCtor.Emit(OpCodes.Nop);
  73. ilgCtor.Emit(OpCodes.Ret);//返回
  74. //定义接口
  75. var pt = typeof(PropertyChangedEventHandler);
  76. typeBuilderProxy.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
  77. var eil = typeBuilderProxy.DefineEvent("PropertyChanged", EventAttributes.SpecialName, typeof(PropertyChangedEventHandler));
  78. //add field
  79. var eb = typeBuilderProxy.DefineField("_PropertyChanged", typeof(PropertyChangedEventHandler), FieldAttributes.Private);
  80. var compareExchange = GetGenericMethod(typeof(Interlocked), "CompareExchange");// finds the correct method to call.
  81. // thanks to @marc, create the specific method with the correct type
  82. compareExchange = compareExchange.MakeGenericMethod(typeof(PropertyChangedEventHandler));
  83. //add methoed
  84. var mas = MethodAttributes.Public | MethodAttributes.HideBySig
  85. | MethodAttributes.NewSlot | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.Final;
  86. var mb = typeBuilderProxy.DefineMethod("add_PropertyChanged", mas, typeof(void), new Type[] { pt });
  87. mb.DefineParameter(0, ParameterAttributes.Retval, null);
  88. mb.DefineParameter(1, ParameterAttributes.None, "value");
  89. var il = mb.GetILGenerator();
  90. il.DeclareLocal(pt);
  91. il.DeclareLocal(pt);
  92. il.DeclareLocal(pt);
  93. il.Emit(OpCodes.Ldarg_0);
  94. il.Emit(OpCodes.Ldfld, eb);
  95. il.Emit(OpCodes.Stloc_0);
  96. var lable = il.DefineLabel();
  97. il.MarkLabel(lable);
  98. il.Emit(OpCodes.Ldloc_0);
  99. il.Emit(OpCodes.Stloc_1);
  100. il.Emit(OpCodes.Ldloc_1);
  101. il.Emit(OpCodes.Ldarg_1);
  102. il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new Type[] { typeof(Delegate), typeof(Delegate) }));
  103. il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
  104. il.Emit(OpCodes.Stloc_2);
  105. il.Emit(OpCodes.Ldarg_0);
  106. il.Emit(OpCodes.Ldflda, eb);
  107. il.Emit(OpCodes.Ldloc_2);
  108. il.Emit(OpCodes.Ldloc_1);
  109. il.Emit(OpCodes.Call, compareExchange);
  110. il.Emit(OpCodes.Stloc_0);
  111. il.Emit(OpCodes.Ldloc_0);
  112. il.Emit(OpCodes.Ldloc_1);
  113. il.Emit(OpCodes.Bne_Un_S, lable);
  114. il.Emit(OpCodes.Ret);
  115. eil.SetAddOnMethod(mb);
  116. //remove event
  117. mb = typeBuilderProxy.DefineMethod("remove_PropertyChanged", mas, typeof(void), new Type[] { pt });
  118. mb.DefineParameter(0, ParameterAttributes.Retval, null);
  119. mb.DefineParameter(1, ParameterAttributes.None, "value");
  120. il = mb.GetILGenerator();
  121. il.DeclareLocal(pt);
  122. il.DeclareLocal(pt);
  123. il.DeclareLocal(pt);
  124. il.Emit(OpCodes.Ldarg_0);
  125. il.Emit(OpCodes.Ldfld, eb);
  126. il.Emit(OpCodes.Stloc_0);
  127. lable = il.DefineLabel();
  128. il.MarkLabel(lable);
  129. il.Emit(OpCodes.Ldloc_0);
  130. il.Emit(OpCodes.Stloc_1);
  131. il.Emit(OpCodes.Ldloc_1);
  132. il.Emit(OpCodes.Ldarg_1);
  133. il.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new Type[] { typeof(Delegate), typeof(Delegate) }));
  134. il.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
  135. il.Emit(OpCodes.Stloc_2);
  136. il.Emit(OpCodes.Ldarg_0);
  137. il.Emit(OpCodes.Ldflda, eb);
  138. il.Emit(OpCodes.Ldloc_2);
  139. il.Emit(OpCodes.Ldloc_1);
  140. il.Emit(OpCodes.Call, compareExchange);
  141. il.Emit(OpCodes.Stloc_0);
  142. il.Emit(OpCodes.Ldloc_0);
  143. il.Emit(OpCodes.Ldloc_1);
  144. il.Emit(OpCodes.Bne_Un_S, lable);
  145. il.Emit(OpCodes.Ret);
  146. eil.SetRemoveOnMethod(mb);
  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. PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty(propertyName, PropertyAttributes.None, typePepropertyInfo, Type.EmptyTypes);
  155. //重写属性的Get Set方法
  156. //Method 搞的一直调用不成功,应该是写的时候没有加上CheckAccessOnOverride
  157. var methodGet = typeBuilderProxy.DefineMethod("get_" + propertyName, GetSetMethodAttributes, typePepropertyInfo, Type.EmptyTypes);
  158. var methodSet = typeBuilderProxy.DefineMethod("set_" + propertyName, GetSetMethodAttributes, typeof(void), new Type[] { typePepropertyInfo });
  159. //il of get method
  160. var ilGetMethod = methodGet.GetILGenerator();
  161. ilGetMethod.Emit(OpCodes.Nop);
  162. ilGetMethod.Emit(OpCodes.Ldstr, "Before Do");
  163. ilGetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
  164. ilGetMethod.Emit(OpCodes.Ldarg_0);
  165. ilGetMethod.Emit(OpCodes.Call, typeNeedProxy.GetMethod("get_" + propertyName));
  166. ilGetMethod.Emit(OpCodes.Ret);
  167. //il of set method
  168. methodSet.DefineParameter(0, ParameterAttributes.Retval, null);
  169. methodSet.DefineParameter(1, ParameterAttributes.None, "value");
  170. ILGenerator ilSetMethod = methodSet.GetILGenerator();
  171. var nullLabel = ilSetMethod.DefineLabel();
  172. ilSetMethod.Emit(OpCodes.Nop);
  173. ilSetMethod.Emit(OpCodes.Ldarg_0);
  174. ilSetMethod.Emit(OpCodes.Ldarg_1);
  175. ilSetMethod.Emit(OpCodes.Call, typeNeedProxy.GetMethod("set_" + propertyName));
  176. ilSetMethod.Emit(OpCodes.Nop);
  177. ilSetMethod.Emit(OpCodes.Ldstr, "Before Do");
  178. ilSetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
  179. ilSetMethod.Emit(OpCodes.Nop);
  180. ilSetMethod.Emit(OpCodes.Ldarg_0);
  181. ilSetMethod.Emit(OpCodes.Ldfld, eb);
  182. ilSetMethod.Emit(OpCodes.Dup);
  183. ilSetMethod.Emit(OpCodes.Brtrue_S, nullLabel);
  184. ilSetMethod.Emit(OpCodes.Pop);
  185. var retLabel = ilSetMethod.DefineLabel();
  186. ilSetMethod.Emit(OpCodes.Br_S, retLabel);
  187. ilSetMethod.MarkLabel(nullLabel);
  188. ilSetMethod.Emit(OpCodes.Ldarg_0);
  189. ilSetMethod.Emit(OpCodes.Ldstr, propertyInfo.Name);
  190. ilSetMethod.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new Type[] { typeof(string) }));
  191. ilSetMethod.Emit(OpCodes.Callvirt, pt.GetMethod("Invoke", new Type[] { typeof(object), typeof(PropertyChangedEventArgs) }));
  192. ilSetMethod.Emit(OpCodes.Nop);
  193. ilSetMethod.Emit(OpCodes.Ldstr, "After Do");
  194. ilSetMethod.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
  195. ilSetMethod.Emit(OpCodes.Nop);
  196. ilSetMethod.MarkLabel(retLabel);
  197. ilSetMethod.Emit(OpCodes.Ret);
  198. //ilSetMethod.Emit(OpCodes.Nop);
  199. //ilSetMethod.Emit(OpCodes.Ldarg_0);
  200. //ilSetMethod.Emit(OpCodes.Ldarg_1);
  201. //ilSetMethod.Emit(OpCodes.Stfld, fieldBuilder);
  202. //ilSetMethod.Emit(OpCodes.Ret);
  203. //设置属性的Get Set方法
  204. propertyBuilder.SetGetMethod(methodGet);
  205. propertyBuilder.SetSetMethod(methodSet);
  206. }
  207. //使用动态类创建类型
  208. Type proxyClassType = typeBuilderProxy.CreateType();
  209. //保存动态创建的程序集
  210. if (isSavaDynamicModule)
  211. assemblyBuilder.Save(DynamicModuleDllName);
  212. //创建类实例
  213. var instance = Activator.CreateInstance(proxyClassType);
  214. return (T)instance;
  215. }
  216. private static MethodInfo GetGenericMethod(Type type, string methodName)
  217. {
  218. var q = from m in type.GetMethods()
  219. where m.Name == methodName && m.IsGenericMethod
  220. select m;
  221. return q.FirstOrDefault();
  222. }
  223. }
  224. }