Beispiel #1
0
        /// <summary>
        /// Implements the interface for the proxy type.
        /// </summary>
        /// <param name="context">The current builder context.</param>
        /// <param name="interfaceType">The interface type.</param>
        private void ImplementInterfaces(ProxyBuilderContext context, Type interfaceType)
        {
            this.ImplementInterface(context, interfaceType);
            var interfaces = interfaceType.GetInterfaces();

            if (interfaces != null)
            {
                foreach (var iface in interfaces)
                {
                    this.ImplementInterfaces(context, iface);
                }
            }
        }
Beispiel #2
0
 /// <summary>
 /// Emits the IL for the <see cref="IProxiedObject"/> interfaces 'ProxiedObject' property.
 /// </summary>
 /// <param name="context">The proxy builder context.</param>
 private void EmitIProxiedObjectInterface(ProxyBuilderContext context)
 {
     var propertyProxiedObject = context
                                 .TypeBuilder
                                 .NewProperty <object>("ProxiedObject")
                                 .Getter(m => m
                                         .Public()
                                         .Virtual()
                                         .HideBySig()
                                         .NewSlot()
                                         .Body()
                                         .LdArg0()
                                         .LdFld(context.BaseObjectField)
                                         .Ret());
 }
Beispiel #3
0
 /// <summary>
 /// Adds a constructor to the proxy type.
 /// </summary>
 /// <param name="context">The current builder context.</param>
 private void EmitConstructor(ProxyBuilderContext context)
 {
     // Build Constructor.
     var constructorBuilder = context
                              .TypeBuilder
                              .NewConstructor()
                              .Public()
                              .HideBySig()
                              .SpecialName()
                              .RTSpecialName()
                              .Param(context.BaseType, "target")
                              .Body()
                              .LdArg0()
                              .LdArg1()
                              .StFld(context.BaseObjectField)
                              .Ret();
 }
Beispiel #4
0
        /// <summary>
        /// Emits the IL to call a proxy method implementation.
        /// </summary>
        /// <param name="context">The proxy builder context.</param>
        /// <param name="methodIL">The methods <see cref="ILGenerator"/>.</param>
        /// <param name="methodInfo">The method to implement.</param>
        /// <param name="methodArgTypes">The methods arguments.</param>
        private void EmitCallToProxyImplementation(
            ProxyBuilderContext context,
            IEmitter methodIL,
            MethodInfo methodInfo,
            Type[] methodArgTypes)
        {
            MethodInfo invokeMethod      = typeof(IProxy).GetMethod("Invoke", new Type[] { typeof(MethodInfo), typeof(object[]) });
            MethodInfo invokeAsyncMethod = typeof(IProxy).GetMethod("InvokeAsync", new Type[] { typeof(MethodInfo), typeof(object[]) });
            MethodInfo makeGenericMethod = typeof(MethodInfo).GetMethod("MakeGenericMethod", new Type[] { typeof(Type[]) });

            methodIL
            .DeclareLocal(typeof(Type[]), out ILocal localGenArgTypes)
            .DeclareLocal(typeof(object[]), out ILocal localArguments)
            .DeclareLocal(typeof(MethodInfo), out ILocal localMethodInfo);

            if (methodInfo.IsGenericMethodDefinition == true)
            {
                Type[] genArgTypes = methodInfo.GetGenericArguments();

                methodIL.Array(
                    typeof(Type),
                    localGenArgTypes,
                    genArgTypes.Length,
                    (index) =>
                {
                    methodIL.EmitTypeOf(genArgTypes[index]);
                });
            }

            methodIL.Nop();

            // Build the arguments array.
            methodIL.Array(
                typeof(object),
                localArguments,
                methodArgTypes.Length,
                (index) =>
            {
                methodIL
                .LdArg(index + 1)
                .Conv(methodArgTypes[index], typeof(object), false);
            });

            methodIL.Nop();

            if (methodInfo.IsGenericMethodDefinition == true)
            {
                // Get the MethodInfo of the method being called on the proxy.
                methodIL
                .EmitMethod(methodInfo, methodInfo.DeclaringType)
                .LdLoc(localGenArgTypes)
                .CallVirt(makeGenericMethod)
                .StLoc(localMethodInfo);
            }
            else
            {
                // Get the MethodInfo of the method being called on the proxy.
                methodIL
                .EmitMethod(methodInfo, methodInfo.DeclaringType)
                .StLoc(localMethodInfo);
            }

            methodIL.Nop();

#if ASYNCCALL
            if (methodInfo.ReturnType == typeof(Task) ||
                (methodInfo.ReturnType.IsGenericType == true && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)))
            {
                var actualReturnType              = methodInfo.ReturnType.GetGenericArguments()[0];
                var asyncTaskExecutorType         = typeof(AsyncTaskExecutor <>).MakeGenericType(actualReturnType);
                var asyncTaskExecutorTypeCtor     = asyncTaskExecutorType.GetConstructor(new[] { typeof(IProxy), typeof(MethodInfo), typeof(object[]) });
                var asyncTaskExecutorExecuteAsync = asyncTaskExecutorType.GetMethod("ExecuteAsync");

                methodIL
                .DeclareLocal(asyncTaskExecutorType, out ILocal localAsyncProxy)
                .DeclareLocal(typeof(Task <>).MakeGenericType(actualReturnType), out ILocal localReturn)

/* class
 */
                .LdArg0()
                .LdFld(context.BaseObjectField)
                .LdLoc(localMethodInfo)
                .LdLoc(localArguments)
                .Newobj(asyncTaskExecutorTypeCtor)
                .StLoc(localAsyncProxy)

                .LdLoc(localAsyncProxy)
                .Call(asyncTaskExecutorExecuteAsync)
                .StLoc(localReturn)

/* Struct
 *                  .LdLocAS(localAsyncProxy)
 *                  .LdArg0()
 *                  .LdFld(context.BaseObjectField)
 *                  .LdLoc(localMethodInfo)
 *                  .LdLoc(localArguments)
 *                  .Call(asyncTaskExecutorTypeCtor)
 *                  .LdLocAS(localAsyncProxy)
 *                  .Call(asyncTaskExecutorExecuteAsync)
 *                  .StLoc(localReturn)
 */

                .LdLoc(localReturn);
            }
            else
#endif
            {
                // Call the proxy implementations invoke method.
                methodIL
                .LdArg0()
                .LdFld(context.BaseObjectField)
                .LdLoc(localMethodInfo)
                .LdLoc(localArguments)
                .CallVirt(invokeMethod);

                // Does the method have a return type?
                if (methodInfo.ReturnType != typeof(void))
                {
                    methodIL.Conv(typeof(object), methodInfo.ReturnType, false);
                }
                else
                {
                    // Remove the returned value
                    methodIL.Pop();
                }

                var parms = methodInfo.GetParameters();
                if (parms.Any() == true)
                {
                    int index = 0;
                    foreach (var parm in parms)
                    {
                        if (parm.IsOut == true)
                        {
                            methodIL
                            .LdArg(parm.Position + 1)
                            .LdLoc(localArguments)
                            .LdcI4(index)
                            .LdElemRef()
                            .StIndRef()
                            .Nop();
                        }

                        index++;
                    }
                }
            }

            methodIL.Ret();
        }
Beispiel #5
0
        /// <summary>
        /// Implements the interface for the proxy type.
        /// </summary>
        /// <param name="context">The current builder context.</param>
        /// <param name="interfaceType">The interface type.</param>
        private void ImplementInterface(ProxyBuilderContext context, Type interfaceType)
        {
            var propertyMethods = new Dictionary <string, IMethodBuilder>();

            foreach (var memberInfo in interfaceType.GetMembers())
            {
                if (memberInfo.MemberType == MemberTypes.Method)
                {
                    MethodInfo methodInfo = (MethodInfo)memberInfo;
                    Type[]     methodArgs = methodInfo
                                            .GetParameters()
                                            .Select(p => p.ParameterType)
                                            .ToArray();

                    Type[] genericArguments = null;
                    var    methodBuilder    = context
                                              .TypeBuilder
                                              .NewMethod(methodInfo.Name)
                                              .MethodAttributes(MethodAttributes.Public | MethodAttributes.Virtual)
                                              .Params(methodArgs)
                                              .Returns(methodInfo.ReturnType);

                    if (methodInfo.ContainsGenericParameters == true)
                    {
                        genericArguments = methodInfo.GetGenericArguments();
                        foreach (var arg in genericArguments)
                        {
                            methodBuilder.NewGenericParameter(arg.Name)
                            .Attributes = arg.GenericParameterAttributes;
                        }
                    }

                    var methodIL = methodBuilder.Body();

                    this.EmitCallToProxyImplementation(context, methodIL, methodInfo, methodArgs);

                    if (methodInfo.IsProperty() == true)
                    {
                        propertyMethods.Add(methodInfo.Name, methodBuilder);
                    }
                }
                else if (memberInfo.MemberType == MemberTypes.Property)
                {
                    var propertyBuilder = context
                                          .TypeBuilder
                                          .NewProperty(memberInfo.Name, ((PropertyInfo)memberInfo).PropertyType)
                                          .Attributes(PropertyAttributes.SpecialName);

                    if (propertyMethods.TryGetValue(
                            memberInfo.PropertyGetName(),
                            out IMethodBuilder getMethod) == true)
                    {
                        propertyBuilder.GetMethod = getMethod;
                    }

                    if (propertyMethods.TryGetValue(
                            memberInfo.PropertySetName(),
                            out IMethodBuilder setMethod) == true)
                    {
                        propertyBuilder.SetMethod = setMethod;
                    }
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// Generate the proxy type.
        /// </summary>
        /// <param name="proxyType">The interface the proxy type must implement.</param>
        /// <param name="proxyTargetType">The target type to receive the proxied calls.</param>
        /// <param name="proxyBaseType">The base type.</param>
        /// <param name="action">An action to allow build type injection.</param>
        /// <param name="proxyOptions">The proxy generation options.</param>
        /// <returns>A <see cref="Type"/> representing the proxy type.</returns>
        private Type GenerateProxyType(
            Type proxyType,
            Type proxyTargetType,
            Type proxyBaseType,
            Action <IProxyBuilderContext> action,
            ProxyOptions proxyOptions = null)
        {
            if (proxyBaseType?.IsInterface == true)
            {
                throw new ArgumentException("Argument cannot be an interface", "proxyBaseType");
            }

            if (proxyType.IsInterface == false &&
                proxyType != proxyBaseType)
            {
                throw new ArgumentException("Argument is not an interface", "proxyType");
            }

            if (typeof(IProxy).IsAssignableFrom(proxyTargetType) == false)
            {
                throw new ArgumentException("Argument does not implement <IProxy>", "proxiedType");
            }

            var typeName = proxyOptions?.TypeName ?? TypeName(proxyType, proxyTargetType);

            var typeBuilder = TypeFactory
                              .Default
                              .NewType(typeName)
                              .Public()
                              .Implements(typeof(IProxiedObject));

            if (proxyType.IsInterface == true)
            {
                typeBuilder.Implements(proxyType);
            }

            if (proxyBaseType != null)
            {
                typeBuilder.InheritsFrom(proxyBaseType);
            }

            var targetField = typeBuilder
                              .NewField <IProxy>("target")
                              .Private();

            var context = new ProxyBuilderContext(
                typeBuilder,
                proxyType,
                proxyTargetType,
                targetField,
                null);

            action?.Invoke(context);

            if (proxyType.IsInterface == true)
            {
                this.ImplementInterfaces(context, context.NewType);
            }

            this.EmitConstructor(context);

            this.EmitIProxiedObjectInterface(context);

            return(context
                   .TypeBuilder
                   .CreateType());
        }