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