private void WeaveTypeProperties(TypeDefinition typeDefinition) { var properties = typeDefinition.Properties.ToArray(); foreach (var propertyDefinition in properties) { var property = propertyDefinition.TryGetPropertyInfo(); if (property == null) { ModuleWeaver.LogInfo($"Property {propertyDefinition.Name} from type {typeDefinition.FullName} will not be weaved because it was not possible to load its corresponding PropertyInfo"); continue; } if (WeavedProperties.ContainsKey(property)) { // if the property we're trying to weave was already weaved we'll skip weaving it // all aspects are applied the first time the property is weaved, there's no need to weave it more than once continue; } else { // mark this property so that it won't be weaved again WeavedProperties.Add(property, true); } var aspects = ModuleWeaver.Setup.GetInterceptPropertyAspects(property).ToArray(); if (aspects.Length <= 0) { ModuleWeaver.LogInfo($"Property {propertyDefinition.Name} from type {typeDefinition.FullName} will not be weaved because no aspect was applied to it"); continue; } // clone the original getter because we're going to rewrite it var clonedGetMethod = propertyDefinition.GetMethod != null?MethodWeaverHelper.CloneMethod(typeDefinition, propertyDefinition.GetMethod) : null; if (clonedGetMethod != null) { typeDefinition.Methods.Add(clonedGetMethod); } // clone the original setter because we're going to rewrite it var clonedSetMethod = propertyDefinition.SetMethod != null?MethodWeaverHelper.CloneMethod(typeDefinition, propertyDefinition.SetMethod) : null; if (clonedSetMethod != null) { typeDefinition.Methods.Add(clonedSetMethod); } // creates a Binding class that inherits from PropertyBinding // this class is used to invoke the aspects in a way that works with generic methods var propertyGenericParameters = (propertyDefinition.GetMethod ?? propertyDefinition.SetMethod).GenericParameters; var bindingTypeDef = MethodWeaverHelper.CreateBindingTypeDef(typeDefinition, typeof(PropertyBinding), propertyDefinition.Name, propertyGenericParameters); // creates the static INSTANCE field that will hold the Binding instance, and adds it to our class var instanceField = MethodWeaverHelper.CreateBindingInstanceField(bindingTypeDef); bindingTypeDef.Fields.Add(instanceField); // creates the constructor of and adds it to our Binding class var ctor = MethodWeaverHelper.CreateBindingCtor(bindingTypeDef, typeof(PropertyBinding), typeof(IInterceptPropertyAspect)); bindingTypeDef.Methods.Add(ctor); // creates the static constructor and adds it to our Binding class var staticCtor = MethodWeaverHelper.CreateBindingStaticCtor(bindingTypeDef, instanceField, ctor, typeof(IInterceptPropertyAspect), aspects); bindingTypeDef.Methods.Add(staticCtor); // adds our Binding class as a nested type of the class that we're weaving typeDefinition.NestedTypes.Add(bindingTypeDef); if (clonedGetMethod != null) { // creates the ProceedGet method that overrides the abstract method PropertyBinding.ProceedGet var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; var abstractProceedGetMethod = ModuleWeaver.ModuleDefinition.ImportReference(typeof(PropertyBinding).GetMethod("ProceedGet", bindingFlags)); var proceedGetMethod = MethodWeaverHelper.CreateBindingProceedMethod(typeDefinition, bindingTypeDef, typeof(PropertyContext), clonedGetMethod, abstractProceedGetMethod, false); bindingTypeDef.Methods.Add(proceedGetMethod); // rewrites the original method so that it calls PropertyBinding.RunGetter MethodWeaverHelper.RewriteOriginalMethod(typeDefinition, bindingTypeDef, nameof(PropertyBinding.RunGetter), typeof(PropertyBinding), typeof(PropertyContext), propertyDefinition.GetMethod, false); } if (clonedSetMethod != null) { // creates the ProceedGet method that overrides the abstract method PropertyBinding.ProceedSet var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; var abstractProceedSetMethod = ModuleWeaver.ModuleDefinition.ImportReference(typeof(PropertyBinding).GetMethod("ProceedSet", bindingFlags)); var proceedSetMethod = MethodWeaverHelper.CreateBindingProceedMethod(typeDefinition, bindingTypeDef, typeof(PropertyContext), clonedSetMethod, abstractProceedSetMethod, false); bindingTypeDef.Methods.Add(proceedSetMethod); // rewrites the original method so that it calls PropertyBinding.RunSetter MethodWeaverHelper.RewriteOriginalMethod(typeDefinition, bindingTypeDef, nameof(PropertyBinding.RunSetter), typeof(PropertyBinding), typeof(PropertyContext), propertyDefinition.SetMethod, false); } } }
private void WeaveTypeMethods(TypeDefinition typeDefinition) { var methods = typeDefinition.Methods.ToArray(); foreach (var originalMethod in methods) { // do not weave property getters/setters because this is done by the IntercetPropertyAspectsWeaver if (originalMethod.IsGetter || originalMethod.IsSetter) { continue; } var method = originalMethod.TryGetMethodBase(); if (method == null) { ModuleWeaver.LogInfo($"Method {originalMethod.Name} from type {typeDefinition.FullName} will not be weaved because it was not possible to load its corresponding MethodBase"); continue; } if (method.IsAbstract) { ModuleWeaver.LogInfo($"Method {originalMethod.Name} from type {typeDefinition.FullName} will not be weaved because it is an abstract method"); continue; } if (WeavedMethods.ContainsKey(method)) { // if the method we're trying to weave was already weaved we'll skip weaving it // all aspects are applied the first time the method is weaved, there's no need to weave it more than once continue; } else { // mark this method so that it won't be weaved again WeavedMethods.Add(method, true); } if (method.IsAsyncMethod()) { // if the method is async (uses the async keyword) we use a different way of getting the aspects of these methods // this is done because aspects of async methods must implement IInterceptAsyncMethodAspect instead of IInterceptMethodAspect var aspects = ModuleWeaver.Setup.GetInterceptAsyncMethodAspects(method).ToArray(); if (aspects.Length <= 0) { ModuleWeaver.LogInfo($"Method {originalMethod.Name} from type {typeDefinition.FullName} will not be weaved because no aspect was applied to it"); continue; } // clone the original method because we're going to rewrite it var clonedMethod = MethodWeaverHelper.CloneMethod(typeDefinition, originalMethod); typeDefinition.Methods.Add(clonedMethod); // creates a Binding class that inherits from AsyncMethodBinding // this class is used to invoke the aspects in a way that works with generic methods var bindingTypeDef = MethodWeaverHelper.CreateBindingTypeDef(typeDefinition, typeof(AsyncMethodBinding), originalMethod.Name, originalMethod.GenericParameters); // creates the static INSTANCE field that will hold the Binding instance, and adds it to our class var instanceField = MethodWeaverHelper.CreateBindingInstanceField(bindingTypeDef); bindingTypeDef.Fields.Add(instanceField); // creates the constructor of and adds it to our Binding class var ctor = MethodWeaverHelper.CreateBindingCtor(bindingTypeDef, typeof(AsyncMethodBinding), typeof(IInterceptAsyncMethodAspect)); bindingTypeDef.Methods.Add(ctor); // creates the static constructor and adds it to our Binding class var staticCtor = MethodWeaverHelper.CreateBindingStaticCtor(bindingTypeDef, instanceField, ctor, typeof(IInterceptAsyncMethodAspect), aspects); bindingTypeDef.Methods.Add(staticCtor); // creates the Proceed method that overrides the abstract method MethodBinding.Proceed/AsyncMethodBinding.Proceed var bindingFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic; var abstractProceedMethod = ModuleWeaver.ModuleDefinition.ImportReference(typeof(AsyncMethodBinding).GetMethod("Proceed", bindingFlags)); var proceedMethod = MethodWeaverHelper.CreateBindingProceedMethod(typeDefinition, bindingTypeDef, typeof(AsyncMethodContext), clonedMethod, abstractProceedMethod, true); bindingTypeDef.Methods.Add(proceedMethod); // adds our Binding class as a nested type of the class that we're weaving typeDefinition.NestedTypes.Add(bindingTypeDef); // rewrites the original method so that it calls AsyncMethodBinding.Run MethodWeaverHelper.RewriteOriginalMethod(typeDefinition, bindingTypeDef, nameof(AsyncMethodBinding.Run), typeof(AsyncMethodBinding), typeof(AsyncMethodContext), originalMethod, true); } else { // if the method is NOT async get the aspects that implement IInterceptMethodAspect var aspects = ModuleWeaver.Setup.GetInterceptMethodAspects(method).ToArray(); if (aspects.Length <= 0) { ModuleWeaver.LogInfo($"Method {originalMethod.Name} from type {typeDefinition.FullName} will not be weaved because no aspect was applied to it"); continue; } // clone the original method because we're going to rewrite it var clonedMethod = MethodWeaverHelper.CloneMethod(typeDefinition, originalMethod); typeDefinition.Methods.Add(clonedMethod); // creates a Binding class that inherits from MethodBinding // this class is used to invoke the aspects in a way that works with generic methods var bindingTypeDef = MethodWeaverHelper.CreateBindingTypeDef(typeDefinition, typeof(MethodBinding), originalMethod.Name, originalMethod.GenericParameters); // creates the static INSTANCE field that will hold the Binding instance, and adds it to our class var instanceField = MethodWeaverHelper.CreateBindingInstanceField(bindingTypeDef); bindingTypeDef.Fields.Add(instanceField); // creates the constructor of and adds it to our Binding class var ctor = MethodWeaverHelper.CreateBindingCtor(bindingTypeDef, typeof(MethodBinding), typeof(IInterceptMethodAspect)); bindingTypeDef.Methods.Add(ctor); // creates the static constructor and adds it to our Binding class var staticCtor = MethodWeaverHelper.CreateBindingStaticCtor(bindingTypeDef, instanceField, ctor, typeof(IInterceptMethodAspect), aspects); bindingTypeDef.Methods.Add(staticCtor); // creates the Proceed method that overrides the abstract method MethodBinding.Proceed/AsyncMethodBinding.Proceed var bindingFlags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic; var abstractProceedMethod = ModuleWeaver.ModuleDefinition.ImportReference(typeof(MethodBinding).GetMethod("Proceed", bindingFlags)); var proceedMethod = MethodWeaverHelper.CreateBindingProceedMethod(typeDefinition, bindingTypeDef, typeof(MethodContext), clonedMethod, abstractProceedMethod, false); bindingTypeDef.Methods.Add(proceedMethod); // adds our Binding class as a nested type of the class that we're weaving typeDefinition.NestedTypes.Add(bindingTypeDef); // rewrites the original method so that it calls MethodBinding.Run MethodWeaverHelper.RewriteOriginalMethod(typeDefinition, bindingTypeDef, nameof(MethodBinding.Run), typeof(MethodBinding), typeof(MethodContext), originalMethod, false); } } }