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 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(); } }