private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint) { var builder = new MethodInterceptorBuilder(this, method, extensionPoint); var taskReturnType = Context.TaskTType.MakeGenericInstanceType(TypeSystem.ObjectReference); var proceed = new MethodDefinition("Proceed", MethodAttributes.Public, taskReturnType); proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType)); builder.Proceed = proceed; builder.Build(); proceed.Body.Emit(il => { builder.EmitCallOriginal(il); // Before we return, we need to wrap the original `Task<T>` into a `Task<object>` var unwrappedReturnType = ((GenericInstanceType)method.ReturnType).GenericArguments[0]; var typedInvoke = asyncInvokerWrap.MakeGenericMethod(unwrappedReturnType); il.Emit(OpCodes.Call, typedInvoke); il.Emit(OpCodes.Ret); }); return(builder); }
private MethodInterceptorBuilder ImplementProceed(MethodDefinition method, ExtensionPointAttribute extensionPoint) { LogInfo($"ImplementProceed: {method.ReturnType}"); var builder = new MethodInterceptorBuilder(this, method, extensionPoint); var proceed = new MethodDefinition("Proceed", MethodAttributes.Public, TypeSystem.ObjectReference); proceed.Parameters.Add(new ParameterDefinition(Context.ObjectArrayType)); builder.Proceed = proceed; builder.Build(); proceed.Body.Emit(il => { builder.EmitCallOriginal(il); if (method.ReturnType.CompareTo(TypeSystem.VoidReference)) { // Void methods won't leave anything on the stack, but the proceed method is expected to return a value il.Emit(OpCodes.Ldnull); } else { // If it's a value type, box it il.EmitBoxIfNeeded(method.ReturnType); } il.Emit(OpCodes.Ret); }); return(builder); }
public void Weave(IMemberDefinition member, ExtensionPointAttribute extensionPoint) { // Debugger.Launch(); var attributeField = CacheAttributeInstance(member, extensionPoint); FieldDefinition memberInfoField; if (member is TypeDefinition) { memberInfoField = null; } else { memberInfoField = member.CacheMemberInfo(); } var type = member is TypeDefinition definition ? definition : member.DeclaringType; type.EmitToConstructor(il => { il.LoadField(attributeField); il.Emit(OpCodes.Ldarg_0); if (member is TypeDefinition) { il.LoadType(type); } else { il.LoadField(memberInfoField); } il.EmitCall(instanceInitializerInitialize); }); }
public void Weave(PropertyDefinition property, ExtensionPointAttribute extensionPoint) { var type = property.DeclaringType; LogInfo($"Weaving property get interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{property.Name}"); var propertyInfoField = property.CachePropertyInfo(); var attributeField = CacheAttributeInstance(property, propertyInfoField, extensionPoint); var method = property.GetMethod; var proceedReference = ImplementProceedGet(method, extensionPoint.AttributeType); // Re-implement method method.Body.Emit(il => { ImplementGetBody(attributeField, propertyInfoField, method, il, proceedReference); }); }
public void Weave(MethodDefinition method, ExtensionPointAttribute extensionPoint) { if (!Context.TaskType.IsAssignableFrom(method.ReturnType)) { return; } LogInfo($"Weaving async method interceptor {extensionPoint.AttributeType.FullName} at {method.Describe()}"); var methodInfoField = method.CacheMethodInfo(); var attributeField = CacheAttributeInstance(method, methodInfoField, extensionPoint); var builder = ImplementProceed(method, extensionPoint); // Re-implement method method.Body.Emit(il => { ImplementBody(method, il, attributeField, methodInfoField, builder); }); }
public void Weave(MethodDefinition method, ExtensionPointAttribute extensionPoint) { // We don't want to intercept both async and non-async when the interceptor implements both interfaces if (Context.TaskType.IsAssignableFrom(method.ReturnType) && asyncMethodInterceptorInterface.IsAssignableFrom(extensionPoint.AttributeType)) { return; } LogInfo($"Weaving method interceptor {extensionPoint.AttributeType.FullName} at {method.Describe()}"); var methodInfoField = method.CacheMethodInfo(); var attributeField = CacheAttributeInstance(method, methodInfoField, extensionPoint); var builder = ImplementProceed(method, extensionPoint); // Re-implement method method.Body.Emit(il => { ImplementBody(method, il, attributeField, methodInfoField, builder); }); }
public void Weave(EventDefinition @event, ExtensionPointAttribute extensionPoint, bool isAdd) { var type = @event.DeclaringType; LogInfo($"Weaving event add interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{@event.Name}"); var eventInfoField = @event.CacheEventInfo(); var attributeField = CacheAttributeInstance(@event, eventInfoField, extensionPoint); LogInfo("Setter is intercepted"); var method = isAdd ? @event.AddMethod : @event.RemoveMethod; var proceedReference = ImplementProceedSet(method, extensionPoint.AttributeType); // Re-implement method method.Body.Emit(il => { ImplementBody(@event, attributeField, eventInfoField, method, il, proceedReference, isAdd ? addEventHandler : removeEventHandler); }); }
public void Weave(PropertyDefinition property, ExtensionPointAttribute extensionPoint) { // if (property.DeclaringType != interceptor.DeclaringType) // Debugger.Launch(); var type = property.DeclaringType; LogInfo($"Weaving property interceptor {extensionPoint.AttributeType.FullName} at {type.FullName}.{property.Name}"); var propertyInfoField = property.CachePropertyInfo(); var attributeField = CacheAttributeInstance(property, propertyInfoField, extensionPoint); LogInfo("Setter is intercepted"); var method = property.SetMethod; var proceedReference = ImplementProceedSet(method, extensionPoint.AttributeType); // Re-implement method method.Body.Emit(il => { ImplementSetBody(property, attributeField, propertyInfoField, method, il, proceedReference); }); }
public void Weave(IMemberDefinition member, ExtensionPointAttribute extensionPoint) { var type = member is TypeDefinition definition ? definition : member.DeclaringType; var attributeField = CacheAttributeInstance(member, extensionPoint); var attributeType = extensionPoint.AttributeType.Resolve(); foreach (var property in attributeType.Properties) { if (property.PropertyType.IsGenericInstance && property.PropertyType.GetElementType().CompareTo(injectedFieldType)) { var propertyType = ((GenericInstanceType)property.PropertyType).GenericArguments[0]; var fieldName = GenerateUniqueName(member, attributeType, property.Name); var injectFieldAttribute = property.GetCustomAttributes(injectFieldAttributeType).SingleOrDefault(); var isStatic = injectFieldAttribute != null && (bool)injectFieldAttribute.ConstructorArguments[0].Value; var fieldAttributes = FieldAttributes.Private; if (isStatic) { fieldAttributes |= FieldAttributes.Static; } var field = new FieldDefinition(fieldName, fieldAttributes, propertyType); type.Fields.Add(field); // Generate accessors var getMethodName = GenerateUniqueName(member, attributeType, $"{property.Name}Getter"); var getMethod = new MethodDefinition(getMethodName, MethodAttributes.Private | MethodAttributes.Static, propertyType); getMethod.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference)); getMethod.Body = new MethodBody(getMethod); getMethod.Body.InitLocals = true; getMethod.Body.Emit(il => { if (!isStatic) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, type); } il.LoadField(field); il.Emit(OpCodes.Ret); }); type.Methods.Add(getMethod); var setMethodName = GenerateUniqueName(member, attributeType, $"{property.Name}Setter"); var setMethod = new MethodDefinition(setMethodName, MethodAttributes.Private | MethodAttributes.Static, TypeSystem.VoidReference); setMethod.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference)); setMethod.Parameters.Add(new ParameterDefinition(propertyType)); setMethod.Body = new MethodBody(setMethod); setMethod.Body.InitLocals = true; setMethod.Body.Emit(il => { if (!isStatic) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, type); } il.Emit(OpCodes.Ldarg_1); il.SaveField(field); il.Emit(OpCodes.Ret); }); type.Methods.Add(setMethod); type.EmitToStaticConstructor(il => { var genericInjectedFieldType = injectedFieldType.MakeGenericInstanceType(propertyType); var injectedFieldConstructor = ModuleDefinition.FindConstructor(genericInjectedFieldType).Bind(genericInjectedFieldType); il.LoadField(attributeField); // Instance on which to set the InjectedField // Instantiate the InjectedField il.EmitLocalMethodDelegate(getMethod, Context.Func2Type, TypeSystem.ObjectReference, propertyType); il.EmitLocalMethodDelegate(setMethod, Context.ActionTypes[2], TypeSystem.ObjectReference, propertyType); il.Emit(OpCodes.Newobj, injectedFieldConstructor); il.EmitCall(property.SetMethod); }); } } }
public override void Execute() { // Debugger.Launch(); var soMeta = ModuleDefinition.FindAssembly("Someta"); CecilExtensions.LogInfo = LogInfo; CecilExtensions.LogWarning = LogWarning; CecilExtensions.LogError = LogError; CecilExtensions.Initialize(ModuleDefinition, TypeSystem, soMeta); var extensionPointInterface = ModuleDefinition.FindType("Someta", "IExtensionPoint", soMeta); var stateExtensionPointInterface = ModuleDefinition.FindType("Someta", "IStateExtensionPoint`1", soMeta, "T"); var stateExtensionPointInterfaceBase = ModuleDefinition.FindType("Someta", "IStateExtensionPoint", soMeta); var propertyGetInterceptorInterface = ModuleDefinition.FindType("Someta", "IPropertyGetInterceptor", soMeta); var propertySetInterceptorInterface = ModuleDefinition.FindType("Someta", "IPropertySetInterceptor", soMeta); var eventAddInterceptorInterface = ModuleDefinition.FindType("Someta", "IEventAddInterceptor", soMeta); var eventRemoveInterceptorInterface = ModuleDefinition.FindType("Someta", "IEventRemoveInterceptor", soMeta); var methodInterceptorInterface = ModuleDefinition.FindType("Someta", "IMethodInterceptor", soMeta); var asyncMethodInterceptorInterface = ModuleDefinition.FindType("Someta", "IAsyncMethodInterceptor", soMeta); var nonPublicAccessInterface = ModuleDefinition.FindType("Someta", "INonPublicAccess", soMeta); var asyncInvoker = ModuleDefinition.FindType("Someta.Helpers", "AsyncInvoker", soMeta); var asyncInvokerWrap = ModuleDefinition.FindMethod(asyncInvoker, "Wrap"); var asyncInvokerUnwrap = ModuleDefinition.FindMethod(asyncInvoker, "Unwrap"); var instanceInitializerInterfaceBase = ModuleDefinition.FindType("Someta", "IInstanceInitializer", soMeta); var instanceInitializerInterface = ModuleDefinition.FindType("Someta", "IInstanceInitializer`1", soMeta, "T"); // var interceptorScopeAttribute = ModuleDefinition.FindType("Someta", "InterceptorScopeAttribute", soMeta); // var requireScopeInterceptorInterface = ModuleDefinition.FindType("Someta", "IRequireScopeInterceptor", soMeta); var extensionPointScopesClass = ModuleDefinition.FindType("Someta", "ExtensionPointScopes", soMeta); var extensionPointScopesClassDefinition = extensionPointScopesClass.Resolve(); // var interceptorScopeInterface = interceptorScopesClassDefinition.NestedTypes.Single(x => x.Name == "Scope"); var extensionPointScopePropertyInterface = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Property"); var extensionPointScopeMethodInterface = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Method"); var extensionPointScopeClassInterface = extensionPointScopesClassDefinition.NestedTypes.Single(x => x.Name == "Class"); var propertyGetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>(); var propertySetInterceptions = new List <(PropertyDefinition, ExtensionPointAttribute)>(); var eventAddInterceptions = new List <(EventDefinition, ExtensionPointAttribute)>(); var eventRemoveInterceptions = new List <(EventDefinition, ExtensionPointAttribute)>(); var methodInterceptions = new List <(MethodDefinition, ExtensionPointAttribute)>(); var asyncMethodInterceptions = new List <(MethodDefinition, ExtensionPointAttribute)>(); var classEnhancers = new List <(TypeDefinition, ExtensionPointAttribute)>(); var stateInterceptions = new List <(IMemberDefinition, ExtensionPointAttribute)>(); var instanceInitializers = new List <(IMemberDefinition, ExtensionPointAttribute)>(); var propertyGetInterceptorWeaver = new PropertyGetInterceptorWeaver(CecilExtensions.Context, propertyGetInterceptorInterface); var propertySetInterceptorWeaver = new PropertySetInterceptorWeaver(CecilExtensions.Context, propertySetInterceptorInterface); var eventInterceptorWeaver = new EventInterceptorWeaver(CecilExtensions.Context); var methodInterceptorWeaver = new MethodInterceptorWeaver(CecilExtensions.Context, methodInterceptorInterface, asyncMethodInterceptorInterface); var asyncMethodInterceptorWeaver = new AsyncMethodInterceptorWeaver(CecilExtensions.Context, asyncMethodInterceptorInterface, asyncInvokerWrap, asyncInvokerUnwrap); var classEnhancerWeaver = new ClassEnhancerWeaver(CecilExtensions.Context); var stateWeaver = new StateWeaver(CecilExtensions.Context); var instanceInitializerWeaver = new InstanceInitializerWeaver(CecilExtensions.Context); // unscopedInterface: If present, and if genericTypes is empty (meaning no specific scope was specified), // unscopedInterface will be checked as a fallback. bool HasScope(ExtensionPointAttribute interceptor, TypeReference interfaceType, ExtensionPointScope scope, TypeReference unscopedInterface = null) { var genericTypes = interceptor.AttributeType.FindGenericInterfaces(interfaceType).ToArray(); foreach (var genericType in genericTypes) { var argument = genericType.GenericArguments[0]; TypeReference scopeInterface = null; switch (scope) { case ExtensionPointScope.Class: scopeInterface = extensionPointScopeClassInterface; break; case ExtensionPointScope.Property: scopeInterface = extensionPointScopePropertyInterface; break; case ExtensionPointScope.Method: scopeInterface = extensionPointScopeMethodInterface; break; } if (argument.CompareTo(scopeInterface)) { return(true); } } // If no scope was specified, we consider the scope satisfied if an unscoped version is satisfied // Furthermore, the scope must match the member type. var isScopeMatchedWithMember = interceptor.Scope == scope; return(unscopedInterface != null && genericTypes.Length == 0 && unscopedInterface.IsAssignableFrom(interceptor.AttributeType) && isScopeMatchedWithMember); } // Inventory candidate classes var allTypes = ModuleDefinition.GetAllTypes(); var assemblyInterceptorAttributes = ModuleDefinition.Assembly .GetCustomAttributesIncludingSubtypes(extensionPointInterface) .ToArray(); ExtensionPointAttribute[] assemblyInterceptors; // If we have any assembly-level interceptors, we create a special state class to hold the attribute instances (since attributes // can contain state, but getting attributes through reflection always returns a new instance. if (assemblyInterceptorAttributes.Any()) { // Debugger.Launch(); var assemblyState = new TypeDefinition("Someta", "AssemblyState", TypeAttributes.Public, TypeSystem.ObjectReference); ModuleDefinition.Types.Add(assemblyState); /* * var constructorWithTarget = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, TypeSystem.VoidReference); * constructorWithTarget.Body.Emit(il => * { * il.Emit(OpCodes.Ret); * }); * assemblyState.Methods.Add(constructorWithTarget); */ CecilExtensions.Context.AssemblyState = assemblyState; assemblyInterceptors = assemblyInterceptorAttributes .Select(x => new ExtensionPointAttribute(assemblyState, ModuleDefinition.Assembly, x, ModuleDefinition.Assembly.CustomAttributes.IndexOf(x), ExtensionPointScope.Assembly)) .ToArray(); foreach (var interceptor in assemblyInterceptors) { var fieldName = interceptor.AttributeType.FullName.Replace(".", "$"); var attributeField = new FieldDefinition(fieldName, FieldAttributes.Static | FieldAttributes.Public, interceptor.AttributeType); var index = ModuleDefinition.Assembly.CustomAttributes.IndexOf(interceptor.Attribute); assemblyState.Fields.Add(attributeField); assemblyState.EmitToStaticConstructor(il => { il.EmitGetAssemblyAttributeByIndex(index, interceptor.AttributeType); il.SaveField(attributeField); }); } } else { assemblyInterceptors = new ExtensionPointAttribute[0]; } // var moduleInterceptors = ModuleDefinition // .GetCustomAttributesIncludingSubtypes(extensionPointInterface) // .Select(x => new ExtensionPointAttribute(null, ModuleDefinition, x, ModuleDefinition.CustomAttributes.IndexOf(x), ExtensionPointScope.Module)) // .ToArray(); // var assemblyAndModuleInterceptors = assemblyInterceptors.Concat(moduleInterceptors).ToArray(); foreach (var type in allTypes) { // We can get into recursion scenarios if we allow extension points on extension points. For now, let's naively prohibit this if (extensionPointInterface.IsAssignableFrom(type)) { continue; } var classInterceptors = type .GetCustomAttributesInAncestry(extensionPointInterface) .Select(x => new ExtensionPointAttribute(x.DeclaringType, x.DeclaringType, x.Attribute, x.DeclaringType.CustomAttributes.IndexOf(x.Attribute), ExtensionPointScope.Class)) .Concat(assemblyInterceptors /*.Select(x => new ExtensionPointAttribute(type, x.DeclaringMember, x.Attribute, x.Index, x.Scope))*/) .ToArray(); foreach (var classInterceptor in classInterceptors) { LogInfo($"Found class interceptor {classInterceptor.AttributeType}"); if (nonPublicAccessInterface.IsAssignableFrom(classInterceptor.AttributeType)) { LogInfo($"Discovered class enhancer {classInterceptor.AttributeType.FullName} at {type.FullName}"); classEnhancers.Add((type, classInterceptor)); } if (HasScope(classInterceptor, stateExtensionPointInterface, ExtensionPointScope.Class, stateExtensionPointInterfaceBase)) { LogInfo($"Discovered class state interceptor {classInterceptor.AttributeType.FullName} at {type.FullName}"); stateInterceptions.Add((type, classInterceptor)); } if (HasScope(classInterceptor, instanceInitializerInterface, ExtensionPointScope.Class, instanceInitializerInterfaceBase)) { LogInfo($"Discovered instance initializer {classInterceptor.AttributeType.FullName} at {type.FullName}"); instanceInitializers.Add((type, classInterceptor)); } } foreach (var property in type.Properties) { var interceptors = property.GetCustomAttributesIncludingSubtypes(extensionPointInterface) .Select(x => new ExtensionPointAttribute(type, property, x, property.CustomAttributes.IndexOf(x), ExtensionPointScope.Property)) .Concat(classInterceptors); foreach (var interceptor in interceptors) { if (propertyGetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered property get interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}"); propertyGetInterceptions.Add((property, interceptor)); } if (propertySetInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered property set interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}"); propertySetInterceptions.Add((property, interceptor)); } if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Property, stateExtensionPointInterfaceBase)) { LogInfo($"Discovered property state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{property.Name}"); stateInterceptions.Add((property, interceptor)); } if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Property, instanceInitializerInterfaceBase)) { LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}"); instanceInitializers.Add((property, interceptor)); } } } foreach (var @event in type.Events) { // Debugger.Launch(); var interceptors = @event.GetCustomAttributesIncludingSubtypes(extensionPointInterface) .Select(x => new ExtensionPointAttribute(type, @event, x, @event.CustomAttributes.IndexOf(x), ExtensionPointScope.Event)) .Concat(classInterceptors); foreach (var interceptor in interceptors) { if (eventAddInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered event add interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}"); eventAddInterceptions.Add((@event, interceptor)); } if (eventRemoveInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered event remove interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{@event.Name}"); eventRemoveInterceptions.Add((@event, interceptor)); } } } foreach (var method in type.Methods.Where(x => !x.IsConstructor)) { var interceptors = method.GetCustomAttributesIncludingSubtypes(extensionPointInterface) .Select(x => new ExtensionPointAttribute(type, method, x, method.CustomAttributes.IndexOf(x), ExtensionPointScope.Method)) .Concat(classInterceptors); foreach (var interceptor in interceptors) { if (methodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}"); methodInterceptions.Add((method, interceptor)); } if (asyncMethodInterceptorInterface.IsAssignableFrom(interceptor.AttributeType)) { LogInfo($"Discovered async method interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}"); asyncMethodInterceptions.Add((method, interceptor)); } if (HasScope(interceptor, stateExtensionPointInterface, ExtensionPointScope.Method, stateExtensionPointInterfaceBase)) { LogInfo($"Discovered method state interceptor {interceptor.AttributeType.FullName} at {type.FullName}.{method.Name}"); stateInterceptions.Add((method, interceptor)); } if (HasScope(interceptor, instanceInitializerInterface, ExtensionPointScope.Method, instanceInitializerInterfaceBase)) { LogInfo($"Discovered instance initializer {interceptor.AttributeType.FullName} at {type.FullName}"); instanceInitializers.Add((method, interceptor)); } } } } foreach (var(property, interceptor) in propertyGetInterceptions) { propertyGetInterceptorWeaver.Weave(property, interceptor); } foreach (var(property, interceptor) in propertySetInterceptions) { propertySetInterceptorWeaver.Weave(property, interceptor); } foreach (var(@event, interceptor) in eventAddInterceptions) { eventInterceptorWeaver.Weave(@event, interceptor, isAdd: true); } foreach (var(@event, interceptor) in eventRemoveInterceptions) { eventInterceptorWeaver.Weave(@event, interceptor, isAdd: false); } foreach (var(method, interceptor) in methodInterceptions) { methodInterceptorWeaver.Weave(method, interceptor); } foreach (var(method, interceptor) in asyncMethodInterceptions) { asyncMethodInterceptorWeaver.Weave(method, interceptor); } foreach (var(type, interceptor) in classEnhancers) { classEnhancerWeaver.Weave(type, interceptor); } foreach (var(member, interceptor) in stateInterceptions) { stateWeaver.Weave(member, interceptor); } foreach (var(type, interceptor) in instanceInitializers) { instanceInitializerWeaver.Weave(type, interceptor); } }
public void Weave(TypeDefinition type, ExtensionPointAttribute extensionPoint) { // Debugger.Launch(); LogInfo($"Weaving class enhancer {extensionPoint.AttributeType.FullName} at {type.FullName}"); // interceptor. // For now, we don't want to impact subclasses since there's no current use case for that. If that changes, // we'll revisit. if (type != extensionPoint.DeclaringType) { return; } var attributeField = CacheAttributeInstance(type, extensionPoint); foreach (var interceptorProperty in extensionPoint.AttributeType.Resolve().Properties) { var injectAccess = interceptorProperty.CustomAttributes.SingleOrDefault(x => x.AttributeType.CompareTo(injectAccessAttribute)); if (injectAccess != null) { // Debugger.Launch(); var key = (string)injectAccess.ConstructorArguments.Single().Value; // Find target method. First try using attributes: var targetMethod = type.Methods.SingleOrDefault(x => x.CustomAttributes .Any(y => injectTargetAttribute.IsAssignableFrom(y.AttributeType) && (string)y.ConstructorArguments[0].Value == key)); if (targetMethod == null) { targetMethod = type.Methods.Single(x => x.Name == key); // Todo: won't work for overloads } // Generate a private static method that forms the accessor that will be assigned // to this property on the associated interceptor in a static initializer. var accessor = new MethodDefinition($"<>__{key}$Accessor", MethodAttributes.Private | MethodAttributes.Static, targetMethod.ReturnType); accessor.Parameters.Add(new ParameterDefinition(TypeSystem.ObjectReference)); foreach (var parameter in targetMethod.Parameters) { accessor.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); } // var delegateType = new TypeDefinition(type.Namespace, accessor.Name + "Type", TypeAttributes.NestedPrivate, Context.DelegateType); // delegateType.Methods.Add(new MethodDefinition("Invoke", MethodAttributes.Public, )) accessor.Body = new MethodBody(accessor); accessor.Body.InitLocals = true; accessor.Body.Emit(il => { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, type); for (var i = 1; i <= targetMethod.Parameters.Count; i++) { il.EmitArgument(accessor, i); } il.EmitCall(targetMethod); il.Emit(OpCodes.Ret); }); type.Methods.Add(accessor); // Now set up the static initializer to assign this to the interceptor property type.EmitToStaticConstructor(il => { var isVoid = targetMethod.ReturnType.CompareTo(TypeSystem.VoidReference); var delegateType = (isVoid ? Context.ActionTypes : Context.FuncTypes)[targetMethod.Parameters.Count + 1]; var typeArguments = new List <TypeReference>(); typeArguments.Add(TypeSystem.ObjectReference); typeArguments.AddRange(targetMethod.Parameters.Select(x => x.ParameterType)); if (!isVoid) { typeArguments.Add(targetMethod.ReturnType); } il.LoadField(attributeField); il.EmitLocalMethodDelegate(accessor, delegateType, typeArguments.ToArray()); il.EmitCall(interceptorProperty.SetMethod); }); } } }
public MethodInterceptorBuilder(BaseWeaver weaver, MethodDefinition method, ExtensionPointAttribute extensionPoint) { this.weaver = weaver; this.method = method; this.extensionPoint = extensionPoint; }