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 Execute() { LogInfo("ReactiveCommandObleak weaving"); // Validate we have the dependencies we need var mscorlib = ModuleDefinition.FindAssembly("mscorlib", LogError); if (mscorlib == null) { return; } var obleakCore = ModuleDefinition.FindAssembly("Obleak.Fody.Core", LogError); if (obleakCore == null) { return; } var reactiveUiCore = ModuleDefinition.FindAssembly("ReactiveUI", LogError); if (reactiveUiCore == null) { return; } // Get the IDisposable and IReactiveCommand types var disposableType = new TypeReference("System", "IDisposable", ModuleDefinition, mscorlib); var disposeableTypeResolved = ModuleDefinition.Import(disposableType).Resolve(); var disposeMethod = ModuleDefinition.Import(disposeableTypeResolved.Methods.First(x => x.Name == "Dispose")); var reactiveCommandType = new TypeReference("ReactiveUI", "IReactiveCommand", ModuleDefinition, reactiveUiCore); var obleakCommandAttribute = ModuleDefinition.FindType("Obleak.Fody.Core", "ObleakReactiveCommandAttribute", obleakCore); if (obleakCommandAttribute == null) { throw new Exception("obleakCommandAttribute is null"); } // Any class where the ObleakCommand attribute appears on a proeprty var targets = ModuleDefinition.GetAllTypes().Where(x => x.IsDefined(obleakCommandAttribute) || x.Properties.Any(y => y.IsDefined(obleakCommandAttribute))); targets.ForEach(target => { LogInfo($"Weaving target: {target.FullName}"); // We can only weave classes which are disposable if (!target.IsDisposable()) { LogError($"Target class {target.FullName} is not disposable and therefore cannot be weaved with Obleak Command"); return; } // Is this for all reactive commands in the class? var isClassWide = target.IsDefined(obleakCommandAttribute); // The command properties we're going to call dispose on var properties = target.Properties.Where(p => (isClassWide || p.IsDefined(obleakCommandAttribute)) && // That implements IReactiveCommand reactiveCommandType.IsAssignableFrom(p.PropertyType) && // And is disposable disposableType.IsAssignableFrom(p.PropertyType)); // If his type doesn't already have a dispose method create one var hasDisposeMethod = target.HasDisposeMethod(); if (!hasDisposeMethod && target.HasGenericParameters) { LogError($"Automatically generating a Dispose method for {target.Name} is not supported due to generics in it's inheritance hierarchy. " + $"You need to create an empty parameterless Dispose() and re-build to use the Obleak weavers"); return; } if (!hasDisposeMethod) { target.CreateDisposeMethod(); } // Find the dispose method and append the instructions at the end to clean up the composite disposable var dispose = target.GetDisposeMethod(); dispose.Body.Emit(il => { var last = dispose.Body.Instructions.Last(i => i.OpCode == OpCodes.Ret && (i.Next == null || dispose.Body.Instructions.Last() == i)); properties.ForEach(p => { var propertyGetMethod = p.GetMethod; // Now load this property, call the get method and then call dispose il.InsertBefore(last, il.Create(OpCodes.Ldarg_0)); // this il.InsertBefore(last, il.Create(OpCodes.Call, propertyGetMethod)); il.InsertBefore(last, il.Create(OpCodes.Callvirt, disposeMethod)); }); }); LogInfo($"Completed weaving target: {target.FullName}"); }); }
public void Execute() { LogInfo("Obleak weaving"); // Validate we have the dependencies we need var rxCore = ModuleDefinition.FindAssembly("System.Reactive.Core", LogError); if (rxCore == null) { return; } var mscorlib = ModuleDefinition.FindAssembly("mscorlib", LogError); if (mscorlib == null) { return; } var obleakCore = ModuleDefinition.FindAssembly("Obleak.Fody.Core", LogError); if (obleakCore == null) { return; } // Get the IDisposable type var disposableType = new TypeReference("System", "IDisposable", ModuleDefinition, mscorlib); // Get the CompositeDisposable type and required methods var compositeDisposableType = new TypeReference("System.Reactive.Disposables", "CompositeDisposable", ModuleDefinition, rxCore); var compositeDisposableTypeResolved = compositeDisposableType.Resolve(); if (compositeDisposableTypeResolved == null) { throw new Exception("compositeDisposableTypeResolved is null"); } var compositeDisposableCtor = ModuleDefinition.Import(compositeDisposableTypeResolved.Methods.Single(m => m.IsConstructor && !m.HasParameters)); var compositeDisposableDisposeMethod = ModuleDefinition.Import(compositeDisposableTypeResolved.Methods.Single(m => m.Name == "Dispose")); var obleakAttribute = ModuleDefinition.FindType("Obleak.Fody.Core", "ObleakSubscriptionAttribute", obleakCore); if (obleakAttribute == null) { throw new Exception("obleakAttribute is null"); } var disposableExtensions = new TypeReference("Obleak.Fody.Core", "Extensions", ModuleDefinition, obleakCore).Resolve(); if (disposableExtensions == null) { throw new Exception("disposableExtensions is null"); } var handleWithExtensionMethod = ModuleDefinition.Import(disposableExtensions.Methods.Single(x => x.Name == "HandleWith")); if (handleWithExtensionMethod == null) { throw new Exception("handleWithExtensionMethod is null"); } // Any class where the Obleak attribute appears on the class, a constructor or a method var targets = ModuleDefinition.GetAllTypes() .Where( x => x.IsDefined(obleakAttribute) || x.GetConstructors().Any(y => y.IsDefined(obleakAttribute)) || x.GetMethods().Any(y => y.IsDefined(obleakAttribute))); targets.ForEach(target => { LogInfo($"Weaving target: {target.FullName}"); // We can only weave classes which are disposable if (!target.IsDisposable()) { LogError($"Target class {target.FullName} is not disposable and therefore cannot be weaved with Obleak"); return; } // If this is class wide process every method, else only tackle what has been attributed. If the class + specific methods / constructors // have the attribute, still process everything // Note: we only need one composite disposable per target type var isClassWide = target.IsDefined(obleakAttribute); // The methods we're going to weave var methods = target.Methods.Where(x => isClassWide || x.IsDefined(obleakAttribute)); // Declare a field for the composite disposable var compositeDisposableField = new FieldDefinition(COMPOSITE_DISPOSABLE_FIELD_NAME + target.Name, FieldAttributes.Private, compositeDisposableType); target.Fields.Add(compositeDisposableField); // Initialise this in all of the constructors in this class (not it's inheritance hierarchy) -- hence target.Methods usage target.Methods.Where(m => m.IsConstructor).ForEach(constructor => { constructor.Body.Emit(il => { var first = constructor.Body.Instructions[0]; // first instruction // Instructions equivalent of: this.$ObleakCompositeDisposable = new CompositeDisposable(); // But as it's done as the first instruction set when decompiled this is actually // private CompositeDisposable $ObleakCompositeDisposable = new CompositeDisposable(); il.InsertBefore(first, il.Create(OpCodes.Ldarg_0)); // this il.InsertBefore(first, il.Create(OpCodes.Newobj, compositeDisposableCtor)); // new CompositeDisposable from ctor il.InsertBefore(first, il.Create(OpCodes.Stfld, compositeDisposableField.BindDefinition(target))); // store new obj in fld }); }); // For every .Subscribe() which returns a disposable call the .Add method on the compositeDisposableField methods.Where(m => m.HasBody && m.Body.Instructions.Any(i => _isExpectedMethodCall(i, disposableType, "Subscribe"))).ForEach(method => { method.Body.Emit(il => { var subscribes = method.Body.Instructions.Where(i => _isExpectedMethodCall(i, disposableType, "Subscribe")).ToArray(); subscribes.ForEach(i => { var next = i.Next; il.InsertBefore(next, il.Create(OpCodes.Ldarg_0)); // this il.InsertBefore(next, il.Create(OpCodes.Ldfld, compositeDisposableField.BindDefinition(target))); il.InsertBefore(next, il.Create(OpCodes.Call, handleWithExtensionMethod)); // Call .HandleWith($ObleakCompositeDisposable) }); }); }); // Does the target itself have a dispose method or is it inheriting the implementation? // If doesn't have one of it's own we need to add one and call the base.Dispose() as we need to clean up this // new local composite disposable. var hasDisposeMethod = target.HasDisposeMethod(); if (!hasDisposeMethod && target.HasGenericParameters) { LogError($"Automatically generating a Dispose method for {target.Name} is not supported due to generics in it's inheritance hierarchy. " + $"You need to create an empty parameterless Dispose() and re-build to use the Obleak weavers"); return; } if (!hasDisposeMethod) { target.CreateDisposeMethod(); } // Find the dispose method and append the instructions at the end to clean up the composite disposable var dispose = target.GetDisposeMethod(); dispose.Body.Emit(il => { var last = dispose.Body.Instructions.Last(i => i.OpCode == OpCodes.Ret && (i.Next == null || dispose.Body.Instructions.Last() == i)); il.InsertBefore(last, il.Create(OpCodes.Ldarg_0)); // this il.InsertBefore(last, il.Create(OpCodes.Ldfld, compositeDisposableField.BindDefinition(target))); il.InsertBefore(last, il.Create(OpCodes.Callvirt, compositeDisposableDisposeMethod)); // call $ObleakCompositeDisposable.Dispose(); }); LogInfo($"Completed weaving target: {target.FullName}"); }); }
public void Execute() { var sexyProxy = ModuleDefinition.FindAssembly("SexyProxy"); if (sexyProxy == null) { LogError("Could not find assembly: SexyProxy (" + string.Join(", ", ModuleDefinition.AssemblyReferences.Select(x => x.Name)) + ")"); return; } var proxyAttribute = ModuleDefinition.FindType("SexyProxy", "ProxyAttribute", sexyProxy); if (proxyAttribute == null) { throw new Exception($"{nameof(proxyAttribute)} is null"); } var proxyForAttribute = ModuleDefinition.FindType("SexyProxy", "ProxyForAttribute", sexyProxy); var doNotProxyAttribute = ModuleDefinition.FindType("SexyProxy", "DoNotProxyAttribute", sexyProxy); var originalMethodAttributeConstructor = ModuleDefinition.FindConstructor(ModuleDefinition.FindType("SexyProxy", "OriginalMethodAttribute", sexyProxy)); var reverseProxyInterface = ModuleDefinition.FindType("SexyProxy", "IReverseProxy", sexyProxy); var proxyInterface = ModuleDefinition.FindType("SexyProxy", "IProxy", sexyProxy); var targetTypes = ModuleDefinition.GetAllTypes().Where(x => x.IsDefined(proxyAttribute, true) || reverseProxyInterface.IsAssignableFrom(x) || proxyInterface.IsAssignableFrom(x)).ToArray(); // Get external proxy references var proxyFors = ModuleDefinition.Assembly.GetCustomAttributes(proxyForAttribute).Select(x => (TypeReference)x.ConstructorArguments.Single().Value).Select(x => x.Resolve()).ToArray(); targetTypes = targetTypes.Concat(proxyFors).ToArray(); var methodInfoType = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(MethodInfo).FullName)); var propertyInfoType = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(PropertyInfo).FullName)); var func2Type = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(Func <,>).FullName)); var action1Type = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(Action <>).FullName)); // for some reason this does not work: // var objectArrayType = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(object[]).FullName)); var objectArrayType = ModuleDefinition.Import(typeof(object[])); var taskType = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(Task).FullName)); var invocationTType = ModuleDefinition.FindType("SexyProxy", "InvocationT`1", sexyProxy, "T"); var asyncInvocationTType = ModuleDefinition.FindType("SexyProxy", "AsyncInvocationT`1", sexyProxy, "T"); var invocationHandlerType = ModuleDefinition.FindType("SexyProxy", "InvocationHandler", sexyProxy); var invocationHandlerIsHandlerActive = ModuleDefinition.FindMethod(invocationHandlerType, "IsHandlerActive"); var voidInvocationType = ModuleDefinition.FindType("SexyProxy", "VoidInvocation", sexyProxy); var voidInvocationConstructor = ModuleDefinition.FindConstructor(voidInvocationType); var voidAsyncInvocationType = ModuleDefinition.FindType("SexyProxy", "VoidAsyncInvocation", sexyProxy); var voidAsyncInvocationConstructor = ModuleDefinition.FindConstructor(voidAsyncInvocationType); var voidInvokeMethod = ModuleDefinition.FindMethod(invocationHandlerType, "VoidInvoke"); var asyncVoidInvokeMethod = ModuleDefinition.FindMethod(invocationHandlerType, "VoidAsyncInvoke"); var invokeTMethod = ModuleDefinition.FindMethod(invocationHandlerType, "InvokeT"); var asyncInvokeTMethod = ModuleDefinition.FindMethod(invocationHandlerType, "AsyncInvokeT"); var objectType = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(object).FullName)); var proxyGetInvocationHandlerMethod = ModuleDefinition.FindGetter(proxyInterface, "InvocationHandler"); var reverseProxyGetInvocationHandlerMethod = ModuleDefinition.FindGetter(reverseProxyInterface, "InvocationHandler"); var invocationType = ModuleDefinition.FindType("SexyProxy", "Invocation", sexyProxy); var invocationGetArguments = ModuleDefinition.FindGetter(invocationType, "Arguments"); var invocationGetProxy = ModuleDefinition.FindGetter(invocationType, "Proxy"); var asyncTaskMethodBuilder = ModuleDefinition.Import(ModuleWeaver.FindType(typeof(AsyncTaskMethodBuilder <>).FullName)); var methodFinder = ModuleDefinition.FindType("SexyProxy.Reflection", "MethodFinder`1", sexyProxy, "T"); var findMethod = ModuleDefinition.FindMethod(methodFinder, "FindMethod"); var findProperty = ModuleDefinition.FindMethod(methodFinder, "FindProperty"); var context = new WeaverContext { ModuleDefinition = ModuleDefinition, LogWarning = LogWarning, LogError = LogError, LogInfo = LogInfo, SexyProxy = sexyProxy, MethodInfoType = methodInfoType, PropertyInfoType = propertyInfoType, Action1Type = action1Type, AsyncInvocationTType = asyncInvocationTType, Func2Type = func2Type, InvocationTType = invocationTType, ObjectArrayType = objectArrayType, TaskType = taskType, AsyncInvokeTMethod = asyncInvokeTMethod, AsyncVoidInvokeMethod = asyncVoidInvokeMethod, InvocationHandlerType = invocationHandlerType, InvocationHandlerIsHandlerActive = invocationHandlerIsHandlerActive, InvokeTMethod = invokeTMethod, ObjectType = objectType, VoidAsyncInvocationConstructor = voidAsyncInvocationConstructor, VoidInvocationConstructor = voidInvocationConstructor, VoidInvokeMethod = voidInvokeMethod, ProxyGetInvocationHandlerMethod = proxyGetInvocationHandlerMethod, ReverseProxyGetInvocationHandlerMethod = reverseProxyGetInvocationHandlerMethod, InvocationType = invocationType, VoidInvocationType = voidInvocationType, VoidAsyncInvocationType = voidAsyncInvocationType, InvocationGetArguments = invocationGetArguments, InvocationGetProxy = invocationGetProxy, AsyncTaskMethodBuilder = asyncTaskMethodBuilder, MethodFinder = methodFinder, FindMethod = findMethod, FindProperty = findProperty, DoNotProxyAttribute = doNotProxyAttribute, OriginalMethodAttributeConstructor = originalMethodAttributeConstructor }; foreach (var sourceType in targetTypes) { LogInfo($"Emitting proxy for {sourceType.FullName}"); ClassWeaver classWeaver; if (sourceType.IsInterface) { classWeaver = new InterfaceClassWeaver(context, sourceType); } else if (proxyInterface.IsAssignableFrom(sourceType)) { classWeaver = new InPlaceClassWeaver(context, sourceType); } else if (reverseProxyInterface.IsAssignableFrom(sourceType)) { classWeaver = new ReverseProxyClassWeaver(context, sourceType); } else { classWeaver = new NonInterfaceClassWeaver(context, sourceType); } classWeaver.Execute(); } }