PageRenderTime 33ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/LinFu.AOP/Extensions/NewOperatorInterceptionExtensions.cs

http://github.com/philiplaureano/LinFu
C# | 274 lines | 118 code | 25 blank | 131 comment | 7 complexity | a301d311e11ae797fd3983bd48fe7097 MD5 | raw file
  1. using System;
  2. using System.Linq;
  3. using LinFu.AOP.Cecil.Interfaces;
  4. using LinFu.AOP.Interfaces;
  5. using Mono.Cecil;
  6. namespace LinFu.AOP.Cecil.Extensions
  7. {
  8. /// <summary>
  9. /// An extension class that adds support for intercepting the 'new' operator with LinFu.AOP.
  10. /// </summary>
  11. public static class NewOperatorInterceptionExtensions
  12. {
  13. /// <summary>
  14. /// Modifies a <paramref name="target" /> to support intercepting all calls to the 'new' operator.
  15. /// </summary>
  16. /// <param name="target">The assembly to be modified.</param>
  17. public static void InterceptAllNewInstances(this AssemblyDefinition target)
  18. {
  19. var typeFilter = GetTypeFilter();
  20. target.InterceptNewInstances(typeFilter);
  21. }
  22. /// <summary>
  23. /// Modifies a <paramref name="target" /> to support intercepting all calls to the 'new' operator.
  24. /// </summary>
  25. /// <param name="target">The assembly to be modified.</param>
  26. public static void InterceptAllNewInstances(this TypeDefinition target)
  27. {
  28. var typeFilter = GetTypeFilter();
  29. target.InterceptNewInstances(typeFilter);
  30. }
  31. /// <summary>
  32. /// Modifies a <paramref name="target" /> to support intercepting calls to the 'new' operator.
  33. /// </summary>
  34. /// <param name="target">The assembly to be modified.</param>
  35. /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
  36. /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
  37. /// <remarks>
  38. /// The type filter determines the concrete types that should be intercepted at runtime.
  39. /// For example, the following functor code intercepts types named "Foo":
  40. /// <code>
  41. /// Func&lt;TypeReference, bool&gt; filter =
  42. /// concreteType => concreteType.Name == "Foo";
  43. /// </code>
  44. /// </remarks>
  45. public static void InterceptNewInstances(this TypeDefinition target, Func<TypeReference, bool> typeFilter,
  46. Func<MethodReference, bool> methodFilter)
  47. {
  48. Func<MethodReference, TypeReference, bool> constructorFilter =
  49. (constructor, declaringType) => methodFilter(constructor) && typeFilter(declaringType);
  50. Func<MethodReference, TypeReference, MethodReference, bool> filter =
  51. (ctor, declaringType, declaringMethod) =>
  52. constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
  53. var redirector = new RedirectNewInstancesToActivator(filter);
  54. target.InterceptNewInstancesWith(redirector, methodFilter);
  55. }
  56. /// <summary>
  57. /// Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
  58. /// </summary>
  59. /// <param name="target">The assembly to be modified.</param>
  60. /// <param name="constructorFilter">The functor that determines which type instantiations should be intercepted.</param>
  61. /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
  62. /// <remarks>
  63. /// The type filter determines which concrete types and constructors should be intercepted at runtime.
  64. /// For example, the following functor code intercepts types named "Foo":
  65. /// <code>
  66. /// Func&lt;MethodReference, TypeReference, bool&gt; filter =
  67. /// (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
  68. /// </code>
  69. /// </remarks>
  70. public static void InterceptNewInstances(this AssemblyDefinition target,
  71. Func<MethodReference, TypeReference, bool> constructorFilter,
  72. Func<MethodReference, bool> methodFilter)
  73. {
  74. Func<MethodReference, TypeReference, MethodReference, bool> filter =
  75. (ctor, declaringType, declaringMethod) =>
  76. constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
  77. var redirector = new RedirectNewInstancesToActivator(filter);
  78. target.InterceptNewInstancesWith(redirector, methodFilter);
  79. }
  80. /// <summary>
  81. /// Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
  82. /// </summary>
  83. /// <param name="target">The assembly to be modified.</param>
  84. /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
  85. /// <remarks>
  86. /// The type filter determines the concrete types that should be intercepted at runtime.
  87. /// For example, the following functor code intercepts types named "Foo":
  88. /// <code>
  89. /// Func&lt;TypeReference, bool&gt; filter =
  90. /// concreteType => concreteType.Name == "Foo";
  91. /// </code>
  92. /// </remarks>
  93. public static void InterceptNewInstances(this AssemblyDefinition target,
  94. Func<TypeReference, bool> typeFilter)
  95. {
  96. target.InterceptNewInstances(typeFilter, m => true);
  97. }
  98. /// <summary>
  99. /// Modifies a <paramref name="target" /> assembly to support intercepting calls to the 'new' operator.
  100. /// </summary>
  101. /// <param name="target">The assembly to be modified.</param>
  102. /// <param name="typeFilter">The functor that determines which type instantiations should be intercepted.</param>
  103. /// <remarks>
  104. /// The type filter determines the concrete types that should be intercepted at runtime.
  105. /// For example, the following functor code intercepts types named "Foo":
  106. /// <code>
  107. /// Func&lt;TypeReference, bool&gt; filter =
  108. /// concreteType => concreteType.Name == "Foo";
  109. /// </code>
  110. /// </remarks>
  111. public static void InterceptNewInstances(this TypeDefinition target, Func<TypeReference, bool> typeFilter)
  112. {
  113. target.InterceptNewInstances(typeFilter, m => true);
  114. }
  115. /// <summary>
  116. /// Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
  117. /// </summary>
  118. /// <param name="target">The item to be modified.</param>
  119. /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
  120. /// <param name="typeFilter">The filter that determines which types will be modified.</param>
  121. /// <remarks>
  122. /// The type filter determines which concrete types and constructors should be intercepted at runtime.
  123. /// For example, the following functor code intercepts types named "Foo":
  124. /// <code>
  125. /// Func&lt;MethodReference, TypeReference, bool&gt; filter =
  126. /// (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
  127. /// </code>
  128. /// </remarks>
  129. public static void InterceptNewInstances(this AssemblyDefinition target,
  130. Func<TypeReference, bool> typeFilter,
  131. Func<MethodReference, bool> methodFilter)
  132. {
  133. Func<MethodReference, TypeReference, bool> constructorFilter =
  134. (constructor, declaringType) => methodFilter(constructor) && typeFilter(declaringType);
  135. Func<MethodReference, TypeReference, MethodReference, bool> filter =
  136. (ctor, declaringType, declaringMethod) =>
  137. constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
  138. var redirector = new RedirectNewInstancesToActivator(filter);
  139. target.InterceptNewInstancesWith(redirector, methodFilter);
  140. }
  141. /// <summary>
  142. /// Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
  143. /// </summary>
  144. /// <param name="target">The item to be modified.</param>
  145. /// <param name="constructorFilter">The functor that determines which type instantiations should be intercepted.</param>
  146. /// <param name="methodFilter">The filter that determines which host methods will be modified</param>
  147. /// <remarks>
  148. /// The type filter determines which concrete types and constructors should be intercepted at runtime.
  149. /// For example, the following functor code intercepts types named "Foo":
  150. /// <code>
  151. /// Func&lt;MethodReference, TypeReference, bool&gt; filter =
  152. /// (constructor, concreteType, hostMethod) => concreteType.Name == "Foo";
  153. /// </code>
  154. /// </remarks>
  155. public static void InterceptNewInstances(this TypeDefinition target,
  156. Func<MethodReference, TypeReference, bool> constructorFilter,
  157. Func<MethodReference, bool> methodFilter)
  158. {
  159. Func<MethodReference, TypeReference, MethodReference, bool> filter =
  160. (ctor, declaringType, declaringMethod) =>
  161. constructorFilter(ctor, declaringType) && methodFilter(declaringMethod);
  162. var redirector = new RedirectNewInstancesToActivator(filter);
  163. target.InterceptNewInstancesWith(redirector, methodFilter);
  164. }
  165. /// <summary>
  166. /// Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
  167. /// </summary>
  168. /// <param name="target">The item to be modified.</param>
  169. /// <param name="newInstanceFilter">The filter that will determine which constructor calls should be intercepted.</param>
  170. /// <param name="methodFilter">
  171. /// The filter that will determine which host methods should be modified to support new instance
  172. /// interception.
  173. /// </param>
  174. public static void InterceptNewInstances(this AssemblyDefinition target,
  175. INewInstanceFilter newInstanceFilter, IMethodFilter methodFilter)
  176. {
  177. var redirector = new RedirectNewInstancesToActivator(newInstanceFilter);
  178. target.InterceptNewInstancesWith(redirector, methodFilter.ShouldWeave);
  179. }
  180. /// <summary>
  181. /// Modifies the <paramref name="target" /> to support intercepting calls to the 'new' operator.
  182. /// </summary>
  183. /// <param name="target">The item to be modified.</param>
  184. /// <param name="newInstanceFilter">The filter that will determine which constructor calls should be intercepted.</param>
  185. /// <param name="methodFilter">
  186. /// The filter that will determine which host methods should be modified to support new instance
  187. /// interception.
  188. /// </param>
  189. public static void InterceptNewInstances(this TypeDefinition target, INewInstanceFilter newInstanceFilter,
  190. IMethodFilter methodFilter)
  191. {
  192. var redirector = new RedirectNewInstancesToActivator(newInstanceFilter);
  193. target.InterceptNewInstancesWith(redirector, methodFilter.ShouldWeave);
  194. }
  195. /// <summary>
  196. /// Modifies the methods in the given <paramref name="target" /> using the custom <see cref="INewObjectWeaver" />
  197. /// instance.
  198. /// </summary>
  199. /// <param name="target">The host that contains the methods that will be modified.</param>
  200. /// <param name="weaver">
  201. /// The custom <see cref="INewObjectWeaver" /> that will replace all calls to the new operator with
  202. /// the custom code emitted by the given weaver.
  203. /// </param>
  204. /// <param name="filter">The method filter that will determine which methods should be modified.</param>
  205. public static void InterceptNewInstancesWith(this AssemblyDefinition target, INewObjectWeaver weaver,
  206. Func<MethodReference, bool> filter)
  207. {
  208. IMethodWeaver interceptNewCalls = new InterceptNewCalls(weaver);
  209. var module = target.MainModule;
  210. var targetMethods = module.Types.SelectMany(t => t.Methods).Where(m => filter(m)).ToArray();
  211. foreach (var targetMethod in targetMethods)
  212. {
  213. interceptNewCalls.Weave(targetMethod);
  214. }
  215. }
  216. /// <summary>
  217. /// Modifies the methods in the given <paramref name="target" /> using the custom <see cref="INewObjectWeaver" />
  218. /// instance.
  219. /// </summary>
  220. /// <param name="target">The host that contains the methods that will be modified.</param>
  221. /// <param name="weaver">
  222. /// The custom <see cref="INewObjectWeaver" /> that will replace all calls to the new operator with
  223. /// the custom code emitted by the given weaver.
  224. /// </param>
  225. /// <param name="filter">The method filter that will determine which methods should be modified.</param>
  226. public static void InterceptNewInstancesWith(this TypeDefinition target, INewObjectWeaver weaver,
  227. Func<MethodReference, bool> filter)
  228. {
  229. var interceptNewCalls = new InterceptNewCalls(weaver);
  230. var targetMethods = target.Methods.Where(m => filter(m)).ToArray();
  231. foreach (var targetMethod in targetMethods)
  232. {
  233. interceptNewCalls.Weave(targetMethod);
  234. }
  235. }
  236. private static Func<TypeReference, bool> GetTypeFilter()
  237. {
  238. return type =>
  239. {
  240. var result = !type.IsValueType;
  241. var module = type.Module;
  242. var moduleName = module.Name;
  243. if (moduleName.StartsWith("LinFu.AOP"))
  244. return false;
  245. return result;
  246. };
  247. }
  248. }
  249. }