Exemplo n.º 1
0
        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);
                    });
                }
            }
        }
Exemplo n.º 2
0
        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();
            }
        }