private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
        {
            MethodAttributes attrs =
                methodToOverride.Attributes & ~MethodAttributes.NewSlot & ~MethodAttributes.Abstract;

            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodToOverride.Name, attrs);

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);
            paramMapper.SetupParameters(methodBuilder);

            methodBuilder.SetReturnType(paramMapper.GetParameterType(methodToOverride.ReturnType));
            methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());

            int paramNum = 1;
            foreach (ParameterInfo pi in methodParameters)
            {
                methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder methodReturn = il.DeclareLocal(typeof(IMethodReturn));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder parameterArray = il.DeclareLocal(typeof(object[]));
            LocalBuilder inputs = il.DeclareLocal(typeof(VirtualMethodInvocation));

            // Create instance of VirtualMethodInvocation
            il.Emit(OpCodes.Ldarg_0); // target object

            il.Emit(OpCodes.Ldtoken, methodToOverride);
            if (methodToOverride.DeclaringType.IsGenericType)
            {
                il.Emit(OpCodes.Ldtoken, methodToOverride.DeclaringType);
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle);
            }
            else
            {
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method
            }

            EmitLoadConstant(il, methodParameters.Length);
            il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters
            if (methodParameters.Length > 0)
            {
                il.Emit(OpCodes.Stloc, parameterArray);

                for (int i = 0; i < methodParameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc, parameterArray);
                    EmitLoadConstant(il, i);
                    EmitLoadArgument(il, i);
                    if (methodParameters[i].ParameterType.IsValueType || methodParameters[i].ParameterType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Box, paramMapper.GetParameterType(methodParameters[i].ParameterType));
                    }
                    else if (methodParameters[i].ParameterType.IsByRef)
                    {
                        Type elementType =  paramMapper.GetElementType(methodParameters[i].ParameterType);
                        il.Emit(OpCodes.Ldobj, elementType);
                        if (elementType.IsValueType || elementType.IsGenericParameter)
                        {
                            il.Emit(OpCodes.Box, elementType);
                        }
                    }

                    il.Emit(OpCodes.Stelem_Ref);
                }

                il.Emit(OpCodes.Ldloc, parameterArray);
            }
            il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation);
            il.Emit(OpCodes.Stloc, inputs);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
            il.Emit(OpCodes.Ldloc, inputs);

            // Put delegate reference onto the stack
            il.Emit(OpCodes.Ldarg_0);
            MethodInfo invokeTarget = delegateMethod;

            if(delegateMethod.IsGenericMethod)
            {
                invokeTarget = delegateMethod.MakeGenericMethod(paramMapper.MappedGenericParameters);
            }

            il.Emit(OpCodes.Ldftn, invokeTarget);
            il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);

            // And call the pipeline
            il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);

            il.Emit(OpCodes.Stloc, methodReturn);

            // Was there an exception?
            Label noException = il.DefineLabel();
            il.Emit(OpCodes.Ldloc, methodReturn);
            il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null);
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Brtrue_S, noException);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Throw);

            il.MarkLabel(noException);

            // handle return value
            if (MethodHasReturnValue)
            {
                il.Emit(OpCodes.Ldloc, methodReturn);
                il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null);
                if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
                {
                    il.Emit(OpCodes.Unbox_Any, paramMapper.GetParameterType(ReturnType));
                }
                else
                {
                    il.Emit(OpCodes.Castclass, paramMapper.GetParameterType(ReturnType));
                }
            }

            // handle byref parameters
            if (methodParameters.Length > 0)
            {
                int outArgIndex = 0;
                foreach (int parameterIndex in OutputParameterIndices)
                {
                    // Get parameter value (the address) onto the stack)
                    Type elementType = paramMapper.GetElementType(methodParameters[parameterIndex].ParameterType);
                    EmitLoadArgument(il, parameterIndex);

                    // Get result of output parameter out of the results array
                    il.Emit(OpCodes.Ldloc, methodReturn);
                    il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs);
                    EmitLoadConstant(il, outArgIndex);
                    il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                    EmitUnboxOrCast(il, elementType);

                    // And store the results
                    il.Emit(OpCodes.Stobj, elementType);
                    ++outArgIndex;
                }
            }

            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }
        private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
        {
            string methodName =
                this.explicitImplementation
                        ? methodToOverride.DeclaringType.Name + "." + methodToOverride.Name
                        : methodToOverride.Name;

            MethodBuilder methodBuilder =
                typeBuilder.DefineMethod(
                    methodName,
                    this.explicitImplementation ? ExplicitImplementationAttributes : ImplicitImplementationAttributes);

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);
            paramMapper.SetupParameters(methodBuilder, this.targetInterfaceParameterMapper);

            methodBuilder.SetReturnType(paramMapper.GetReturnType());
            methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());
            if (this.explicitImplementation)
            {
                this.typeBuilder.DefineMethodOverride(methodBuilder, this.methodToOverride);
            }

            int paramNum = 1;
            foreach (ParameterInfo pi in methodParameters)
            {
                methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder methodReturn = il.DeclareLocal(typeof(IMethodReturn));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder parameterArray = il.DeclareLocal(typeof(object[]));
            LocalBuilder inputs = il.DeclareLocal(typeof(VirtualMethodInvocation));

            // Create instance of VirtualMethodInvocation
            il.Emit(OpCodes.Ldarg_0); // target object

            // If we have a targetField, that means we're building a proxy and
            // should use it as the target object. If we don't, we're building
            // a type interceptor and should leave the this pointer as the
            // target.
            if (targetField != null)
            {
                il.Emit(OpCodes.Ldfld, targetField);
            }

            // If we have a generic method, we want to make sure we're using the open constructed generic method
            // so when a closed generic version of the method is invoked the actual type parameters are used
            il.Emit(
                OpCodes.Ldtoken,
                methodToOverride.IsGenericMethodDefinition
                    ? methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters)
                    : methodToOverride);
            if (methodToOverride.DeclaringType.IsGenericType)
            {
                // if the declaring type is generic, we need to get the method from the target type
                il.Emit(OpCodes.Ldtoken, targetInterface);
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle);
            }
            else
            {
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method
            }

            EmitLoadConstant(il, methodParameters.Length);
            il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters
            if (methodParameters.Length > 0)
            {
                il.Emit(OpCodes.Stloc, parameterArray);

                for (int i = 0; i < methodParameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc, parameterArray);
                    EmitLoadConstant(il, i);
                    EmitLoadArgument(il, i);
                    Type elementType = paramMapper.GetParameterType(methodParameters[i].ParameterType);
                    if (elementType.IsByRef)
                    {
                        elementType = paramMapper.GetElementType(methodParameters[i].ParameterType);
                        il.Emit(OpCodes.Ldobj, elementType);
                    }
                    EmitBox(il, elementType);
                    il.Emit(OpCodes.Stelem_Ref);
                }

                il.Emit(OpCodes.Ldloc, parameterArray);
            }
            il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation);
            il.Emit(OpCodes.Stloc, inputs);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
            il.Emit(OpCodes.Ldloc, inputs);

            // Put delegate reference onto the stack
            il.Emit(OpCodes.Ldarg_0);

            MethodInfo callTarget = delegateMethod;
            if (callTarget.IsGenericMethod)
            {
                callTarget = delegateMethod.MakeGenericMethod(paramMapper.GenericMethodParameters);
            }

            il.Emit(OpCodes.Ldftn, callTarget);

            il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);

            // And call the pipeline
            il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);

            il.Emit(OpCodes.Stloc, methodReturn);

            // Was there an exception?
            Label noException = il.DefineLabel();
            il.Emit(OpCodes.Ldloc, methodReturn);
            il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null);
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Brtrue_S, noException);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Throw);

            il.MarkLabel(noException);

            // Unpack any ref/out parameters
            if (methodParameters.Length > 0)
            {
                int outputArgNum = 0;
                for (paramNum = 0; paramNum < methodParameters.Length; ++paramNum)
                {
                    ParameterInfo pi = methodParameters[paramNum];
                    if (pi.ParameterType.IsByRef)
                    {
                        // Get the original parameter value - address of the ref or out
                        EmitLoadArgument(il, paramNum);

                        // Get the value of this output parameter out of the Outputs collection
                        il.Emit(OpCodes.Ldloc, methodReturn);
                        il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs);
                        EmitLoadConstant(il, outputArgNum++);
                        il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                        EmitUnboxOrCast(il, paramMapper.GetElementType(pi.ParameterType));

                        // And store in the caller
                        il.Emit(OpCodes.Stobj, paramMapper.GetElementType(pi.ParameterType));
                    }
                }
            }

            if (MethodHasReturnValue)
            {
                il.Emit(OpCodes.Ldloc, methodReturn);
                il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null);
                EmitUnboxOrCast(il, paramMapper.GetReturnType());
            }
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }
        private MethodBuilder CreateDelegateImplementation(MethodInfo callBaseMethod)
        {
            string methodName = CreateMethodName("DelegateImplementation");

            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName,
                MethodAttributes.Private | MethodAttributes.HideBySig);
            List<LocalBuilder> outOrRefLocals = new List<LocalBuilder>();

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);
            paramMapper.SetupParameters(methodBuilder);

            methodBuilder.SetReturnType(typeof(IMethodReturn));
            // Adding parameters
            methodBuilder.SetParameters(typeof(IMethodInvocation), typeof(GetNextInterceptionBehaviorDelegate));
            // Parameter 
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "inputs");
            // Parameter 
            methodBuilder.DefineParameter(2, ParameterAttributes.None, "getNext");

            methodBuilder.SetCustomAttribute(new CustomAttributeBuilder(CompilerGeneratedAttributeMethods.CompilerGeneratedAttribute, new object[0]));

            ILGenerator il = methodBuilder.GetILGenerator();

            if (!this.methodToOverride.IsAbstract)
            {
                Label done = il.DefineLabel();
                LocalBuilder ex = il.DeclareLocal(typeof(Exception));

                LocalBuilder baseReturn = null;
                LocalBuilder parameters = null;
                if (MethodHasReturnValue)
                {
                    baseReturn = il.DeclareLocal(paramMapper.GetParameterType(methodToOverride.ReturnType));
                }
                LocalBuilder retval = il.DeclareLocal(typeof(IMethodReturn));

                il.BeginExceptionBlock();
                // Call the base method
                il.Emit(OpCodes.Ldarg_0);

                if (methodParameters.Length > 0)
                {
                    parameters = il.DeclareLocal(typeof(IParameterCollection));
                    il.Emit(OpCodes.Ldarg_1);
                    il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.GetArguments, null);
                    il.Emit(OpCodes.Stloc, parameters);

                    for (int i = 0; i < methodParameters.Length; ++i)
                    {
                        il.Emit(OpCodes.Ldloc, parameters);
                        EmitLoadConstant(il, i);
                        il.EmitCall(OpCodes.Callvirt, IListMethods.GetItem, null);

                        if (methodParameters[i].ParameterType.IsByRef)
                        {
                            // For out or ref, create a local variable for it, initialize, and
                            // pass address of the local to the base class call.
                            Type referredToType = paramMapper.GetElementType(methodParameters[i].ParameterType);
                            LocalBuilder refShadow = il.DeclareLocal(referredToType);
                            outOrRefLocals.Add(refShadow);
                            EmitUnboxOrCast(il, referredToType);

                            il.Emit(OpCodes.Stloc, refShadow);
                            il.Emit(OpCodes.Ldloca, refShadow);
                        }
                        else
                        {
                            EmitUnboxOrCast(il, paramMapper.GetParameterType(methodParameters[i].ParameterType));
                        }
                    }
                }

                MethodInfo baseTarget = callBaseMethod;
                if(baseTarget.IsGenericMethod)
                {
                    baseTarget = callBaseMethod.MakeGenericMethod(paramMapper.MappedGenericParameters);
                }

                il.Emit(OpCodes.Call, baseTarget);

                if (MethodHasReturnValue)
                {
                    il.Emit(OpCodes.Stloc, baseReturn);
                }

                // Generate  the return value
                il.Emit(OpCodes.Ldarg_1);
                if (MethodHasReturnValue)
                {
                    il.Emit(OpCodes.Ldloc, baseReturn);
                    if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Box, paramMapper.GetParameterType(ReturnType));
                    }
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }

                // Set up output parameters - note the collection returned to the
                // IMethodReturn object contains ALL parameter values, inputs and
                // outputs.
                EmitLoadConstant(il, methodParameters.Length);
                il.Emit(OpCodes.Newarr, typeof(object));

                if (methodParameters.Length > 0)
                {
                    LocalBuilder outputParamArray = il.DeclareLocal(typeof(object[]));
                    il.Emit(OpCodes.Stloc, outputParamArray);

                    int outputParameterNum = 0;
                    for (int paramNum = 0; paramNum < methodParameters.Length; ++paramNum)
                    {
                        il.Emit(OpCodes.Ldloc, outputParamArray);
                        EmitLoadConstant(il, paramNum);
                        if (methodParameters[paramNum].ParameterType.IsByRef)
                        {
                            il.Emit(OpCodes.Ldloc, outOrRefLocals[outputParameterNum]);
                            EmitBox(il, outOrRefLocals[outputParameterNum].LocalType);
                            ++outputParameterNum;
                        }
                        else
                        {
                            il.Emit(OpCodes.Ldloc, parameters);
                            EmitLoadConstant(il, paramNum);
                            il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                        }
                        il.Emit(OpCodes.Stelem_Ref);
                    }
                    il.Emit(OpCodes.Ldloc, outputParamArray);
                }

                il.Emit(OpCodes.Callvirt, IMethodInvocationMethods.CreateReturn);
                il.Emit(OpCodes.Stloc, retval);
                il.BeginCatchBlock(typeof(Exception));
                il.Emit(OpCodes.Stloc, ex);
                // Create an exception return
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldloc, ex);
                il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null);
                il.Emit(OpCodes.Stloc, retval);
                il.EndExceptionBlock();
                il.MarkLabel(done);
                il.Emit(OpCodes.Ldloc, retval);
                il.Emit(OpCodes.Ret);
            }
            else
            {
                #region exception-throwing implementation

                il.Emit(OpCodes.Ldarg_1);
                il.EmitCall(OpCodes.Call, BuildAbstractMethodInvokedExceptionMethod, null);
                il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null);
                il.Emit(OpCodes.Ret);

                #endregion
            }

            return methodBuilder;
        }
Exemple #4
0
        private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
        {
            MethodAttributes attrs =
                methodToOverride.Attributes & ~MethodAttributes.NewSlot & ~MethodAttributes.Abstract;

            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodToOverride.Name, attrs);

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);

            paramMapper.SetupParameters(methodBuilder, this.targetTypeParameterMapper);

            methodBuilder.SetReturnType(paramMapper.GetParameterType(methodToOverride.ReturnType));
            methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());

            int paramNum = 1;

            foreach (ParameterInfo pi in methodParameters)
            {
                methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder methodReturn   = il.DeclareLocal(typeof(IMethodReturn));
            LocalBuilder ex             = il.DeclareLocal(typeof(Exception));
            LocalBuilder parameterArray = il.DeclareLocal(typeof(object[]));
            LocalBuilder inputs         = il.DeclareLocal(typeof(VirtualMethodInvocation));

            // Create instance of VirtualMethodInvocation
            il.Emit(OpCodes.Ldarg_0); // target object

            // If we have a generic method, we want to make sure we're using the open constructed generic method
            // so when a closed generic version of the method is invoked the actual type parameters are used
            il.Emit(
                OpCodes.Ldtoken,
                methodToOverride.IsGenericMethodDefinition
                    ? methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters)
                    : methodToOverride);
            if (methodToOverride.DeclaringType.IsGenericType)
            {
                // if the declaring type is generic, we need to get the method from the target type
                il.Emit(OpCodes.Ldtoken, targetType);
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle);
            }
            else
            {
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method
            }

            EmitLoadConstant(il, methodParameters.Length);
            il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters
            if (methodParameters.Length > 0)
            {
                il.Emit(OpCodes.Stloc, parameterArray);

                for (int i = 0; i < methodParameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc, parameterArray);
                    EmitLoadConstant(il, i);
                    EmitLoadArgument(il, i);
                    if (methodParameters[i].ParameterType.IsValueType || methodParameters[i].ParameterType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Box, paramMapper.GetParameterType(methodParameters[i].ParameterType));
                    }
                    else if (methodParameters[i].ParameterType.IsByRef)
                    {
                        Type elementType = paramMapper.GetElementType(methodParameters[i].ParameterType);
                        il.Emit(OpCodes.Ldobj, elementType);
                        if (elementType.IsValueType || elementType.IsGenericParameter)
                        {
                            il.Emit(OpCodes.Box, elementType);
                        }
                    }

                    il.Emit(OpCodes.Stelem_Ref);
                }

                il.Emit(OpCodes.Ldloc, parameterArray);
            }
            il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation);
            il.Emit(OpCodes.Stloc, inputs);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
            il.Emit(OpCodes.Ldloc, inputs);

            // Put delegate reference onto the stack
            il.Emit(OpCodes.Ldarg_0);

            MethodInfo invokeTarget = delegateMethod;

            if (delegateMethod.IsGenericMethod)
            {
                invokeTarget = delegateMethod.MakeGenericMethod(paramMapper.GenericMethodParameters);
            }

            il.Emit(OpCodes.Ldftn, invokeTarget);
            il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);

            // And call the pipeline
            il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);

            il.Emit(OpCodes.Stloc, methodReturn);

            // Was there an exception?
            Label noException = il.DefineLabel();

            il.Emit(OpCodes.Ldloc, methodReturn);
            il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null);
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Brtrue_S, noException);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Throw);

            il.MarkLabel(noException);

            // handle return value
            if (MethodHasReturnValue)
            {
                il.Emit(OpCodes.Ldloc, methodReturn);
                il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null);
                if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
                {
                    il.Emit(OpCodes.Unbox_Any, paramMapper.GetReturnType());
                }
                else
                {
                    il.Emit(OpCodes.Castclass, paramMapper.GetReturnType());
                }
            }

            // handle byref parameters
            if (methodParameters.Length > 0)
            {
                int outArgIndex = 0;
                foreach (int parameterIndex in OutputParameterIndices)
                {
                    // Get parameter value (the address) onto the stack)
                    Type elementType = paramMapper.GetElementType(methodParameters[parameterIndex].ParameterType);
                    EmitLoadArgument(il, parameterIndex);

                    // Get result of output parameter out of the results array
                    il.Emit(OpCodes.Ldloc, methodReturn);
                    il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs);
                    EmitLoadConstant(il, outArgIndex);
                    il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                    EmitUnboxOrCast(il, elementType);

                    // And store the results
                    il.Emit(OpCodes.Stobj, elementType);
                    ++outArgIndex;
                }
            }

            il.Emit(OpCodes.Ret);

            return(methodBuilder);
        }
Exemple #5
0
        private MethodBuilder CreateDelegateImplementation(MethodInfo callBaseMethod)
        {
            string methodName = CreateMethodName("DelegateImplementation");

            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName,
                                                                   MethodAttributes.Private | MethodAttributes.HideBySig);
            List <LocalBuilder> outOrRefLocals = new List <LocalBuilder>();

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);

            paramMapper.SetupParameters(methodBuilder, this.targetTypeParameterMapper);

            methodBuilder.SetReturnType(typeof(IMethodReturn));
            // Adding parameters
            methodBuilder.SetParameters(typeof(IMethodInvocation), typeof(GetNextInterceptionBehaviorDelegate));
            // Parameter
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "inputs");
            // Parameter
            methodBuilder.DefineParameter(2, ParameterAttributes.None, "getNext");

            methodBuilder.SetCustomAttribute(new CustomAttributeBuilder(CompilerGeneratedAttributeMethods.CompilerGeneratedAttribute, new object[0]));

            ILGenerator il = methodBuilder.GetILGenerator();

            if (!this.methodToOverride.IsAbstract)
            {
                Label        done = il.DefineLabel();
                LocalBuilder ex   = il.DeclareLocal(typeof(Exception));

                LocalBuilder baseReturn = null;
                LocalBuilder parameters = null;
                if (MethodHasReturnValue)
                {
                    baseReturn = il.DeclareLocal(paramMapper.GetParameterType(methodToOverride.ReturnType));
                }
                LocalBuilder retval = il.DeclareLocal(typeof(IMethodReturn));

                il.BeginExceptionBlock();
                // Call the base method
                il.Emit(OpCodes.Ldarg_0);

                if (methodParameters.Length > 0)
                {
                    parameters = il.DeclareLocal(typeof(IParameterCollection));
                    il.Emit(OpCodes.Ldarg_1);
                    il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.GetArguments, null);
                    il.Emit(OpCodes.Stloc, parameters);

                    for (int i = 0; i < methodParameters.Length; ++i)
                    {
                        il.Emit(OpCodes.Ldloc, parameters);
                        EmitLoadConstant(il, i);
                        il.EmitCall(OpCodes.Callvirt, IListMethods.GetItem, null);

                        if (methodParameters[i].ParameterType.IsByRef)
                        {
                            // For out or ref, create a local variable for it, initialize, and
                            // pass address of the local to the base class call.
                            Type         referredToType = paramMapper.GetElementType(methodParameters[i].ParameterType);
                            LocalBuilder refShadow      = il.DeclareLocal(referredToType);
                            outOrRefLocals.Add(refShadow);
                            EmitUnboxOrCast(il, referredToType);

                            il.Emit(OpCodes.Stloc, refShadow);
                            il.Emit(OpCodes.Ldloca, refShadow);
                        }
                        else
                        {
                            EmitUnboxOrCast(il, paramMapper.GetParameterType(methodParameters[i].ParameterType));
                        }
                    }
                }

                MethodInfo baseTarget = callBaseMethod;
                if (baseTarget.IsGenericMethod)
                {
                    baseTarget = callBaseMethod.MakeGenericMethod(paramMapper.GenericMethodParameters);
                }

                il.Emit(OpCodes.Call, baseTarget);

                if (MethodHasReturnValue)
                {
                    il.Emit(OpCodes.Stloc, baseReturn);
                }

                // Generate  the return value
                il.Emit(OpCodes.Ldarg_1);
                if (MethodHasReturnValue)
                {
                    il.Emit(OpCodes.Ldloc, baseReturn);
                    if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Box, paramMapper.GetReturnType());
                    }
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }

                // Set up output parameters - note the collection returned to the
                // IMethodReturn object contains ALL parameter values, inputs and
                // outputs.
                EmitLoadConstant(il, methodParameters.Length);
                il.Emit(OpCodes.Newarr, typeof(object));

                if (methodParameters.Length > 0)
                {
                    LocalBuilder outputParamArray = il.DeclareLocal(typeof(object[]));
                    il.Emit(OpCodes.Stloc, outputParamArray);

                    int outputParameterNum = 0;
                    for (int paramNum = 0; paramNum < methodParameters.Length; ++paramNum)
                    {
                        il.Emit(OpCodes.Ldloc, outputParamArray);
                        EmitLoadConstant(il, paramNum);
                        if (methodParameters[paramNum].ParameterType.IsByRef)
                        {
                            il.Emit(OpCodes.Ldloc, outOrRefLocals[outputParameterNum]);
                            EmitBox(il, outOrRefLocals[outputParameterNum].LocalType);
                            ++outputParameterNum;
                        }
                        else
                        {
                            il.Emit(OpCodes.Ldloc, parameters);
                            EmitLoadConstant(il, paramNum);
                            il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                        }
                        il.Emit(OpCodes.Stelem_Ref);
                    }
                    il.Emit(OpCodes.Ldloc, outputParamArray);
                }

                il.Emit(OpCodes.Callvirt, IMethodInvocationMethods.CreateReturn);
                il.Emit(OpCodes.Stloc, retval);
                il.BeginCatchBlock(typeof(Exception));
                il.Emit(OpCodes.Stloc, ex);
                // Create an exception return
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldloc, ex);
                il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null);
                il.Emit(OpCodes.Stloc, retval);
                il.EndExceptionBlock();
                il.MarkLabel(done);
                il.Emit(OpCodes.Ldloc, retval);
                il.Emit(OpCodes.Ret);
            }
            else
            {
                // exception-throwing implementation
                il.Emit(OpCodes.Ldarg_1);
                il.EmitCall(OpCodes.Call, BuildAbstractMethodInvokedExceptionMethod, null);
                il.EmitCall(OpCodes.Callvirt, IMethodInvocationMethods.CreateExceptionMethodReturn, null);
                il.Emit(OpCodes.Ret);
            }

            return(methodBuilder);
        }
        private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
        {
            string methodName =
                this.explicitImplementation
                        ? methodToOverride.DeclaringType.Name + "." + methodToOverride.Name
                        : methodToOverride.Name;

            MethodBuilder methodBuilder =
                typeBuilder.DefineMethod(
                    methodName,
                    this.explicitImplementation ? ExplicitImplementationAttributes : ImplicitImplementationAttributes);

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);

            paramMapper.SetupParameters(methodBuilder, this.targetInterfaceParameterMapper);

            methodBuilder.SetReturnType(paramMapper.GetReturnType());
            methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());
            if (this.explicitImplementation)
            {
                this.typeBuilder.DefineMethodOverride(methodBuilder, this.methodToOverride);
            }

            int paramNum = 1;

            foreach (ParameterInfo pi in methodParameters)
            {
                methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder methodReturn   = il.DeclareLocal(typeof(IMethodReturn));
            LocalBuilder ex             = il.DeclareLocal(typeof(Exception));
            LocalBuilder parameterArray = il.DeclareLocal(typeof(object[]));
            LocalBuilder inputs         = il.DeclareLocal(typeof(VirtualMethodInvocation));

            // Create instance of VirtualMethodInvocation
            il.Emit(OpCodes.Ldarg_0); // target object

            // If we have a targetField, that means we're building a proxy and
            // should use it as the target object. If we don't, we're building
            // a type interceptor and should leave the this pointer as the
            // target.
            if (targetField != null)
            {
                il.Emit(OpCodes.Ldfld, targetField);
            }

            // If we have a generic method, we want to make sure we're using the open constructed generic method
            // so when a closed generic version of the method is invoked the actual type parameters are used
            il.Emit(
                OpCodes.Ldtoken,
                methodToOverride.IsGenericMethodDefinition
                    ? methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters)
                    : methodToOverride);
            if (methodToOverride.DeclaringType.IsGenericType)
            {
                // if the declaring type is generic, we need to get the method from the target type
                il.Emit(OpCodes.Ldtoken, targetInterface);
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle);
            }
            else
            {
                il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method
            }

            EmitLoadConstant(il, methodParameters.Length);
            il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters
            if (methodParameters.Length > 0)
            {
                il.Emit(OpCodes.Stloc, parameterArray);

                for (int i = 0; i < methodParameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc, parameterArray);
                    EmitLoadConstant(il, i);
                    EmitLoadArgument(il, i);
                    Type elementType = paramMapper.GetParameterType(methodParameters[i].ParameterType);
                    if (elementType.IsByRef)
                    {
                        elementType = paramMapper.GetElementType(methodParameters[i].ParameterType);
                        il.Emit(OpCodes.Ldobj, elementType);
                    }
                    EmitBox(il, elementType);
                    il.Emit(OpCodes.Stelem_Ref);
                }

                il.Emit(OpCodes.Ldloc, parameterArray);
            }
            il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation);
            il.Emit(OpCodes.Stloc, inputs);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
            il.Emit(OpCodes.Ldloc, inputs);

            // Put delegate reference onto the stack
            il.Emit(OpCodes.Ldarg_0);

            MethodInfo callTarget = delegateMethod;

            if (callTarget.IsGenericMethod)
            {
                callTarget = delegateMethod.MakeGenericMethod(paramMapper.GenericMethodParameters);
            }

            il.Emit(OpCodes.Ldftn, callTarget);

            il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);

            // And call the pipeline
            il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);

            il.Emit(OpCodes.Stloc, methodReturn);

            // Was there an exception?
            Label noException = il.DefineLabel();

            il.Emit(OpCodes.Ldloc, methodReturn);
            il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null);
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ceq);
            il.Emit(OpCodes.Brtrue_S, noException);
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Throw);

            il.MarkLabel(noException);

            // Unpack any ref/out parameters
            if (methodParameters.Length > 0)
            {
                int outputArgNum = 0;
                for (paramNum = 0; paramNum < methodParameters.Length; ++paramNum)
                {
                    ParameterInfo pi = methodParameters[paramNum];
                    if (pi.ParameterType.IsByRef)
                    {
                        // Get the original parameter value - address of the ref or out
                        EmitLoadArgument(il, paramNum);

                        // Get the value of this output parameter out of the Outputs collection
                        il.Emit(OpCodes.Ldloc, methodReturn);
                        il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs);
                        EmitLoadConstant(il, outputArgNum++);
                        il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
                        EmitUnboxOrCast(il, paramMapper.GetElementType(pi.ParameterType));

                        // And store in the caller
                        il.Emit(OpCodes.Stobj, paramMapper.GetElementType(pi.ParameterType));
                    }
                }
            }

            if (MethodHasReturnValue)
            {
                il.Emit(OpCodes.Ldloc, methodReturn);
                il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null);
                EmitUnboxOrCast(il, paramMapper.GetReturnType());
            }
            il.Emit(OpCodes.Ret);

            return(methodBuilder);
        }
        private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod, int porpertyIndex, FieldBuilder propsField)
        {
            MethodAttributes attrs =
                methodToOverride.Attributes & ~MethodAttributes.NewSlot & ~MethodAttributes.Abstract;

            MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodToOverride.Name, attrs);

            var paramMapper = new MethodOverrideParameterMapper(methodToOverride);

            paramMapper.SetupParameters(methodBuilder, this.targetTypeParameterMapper);

            methodBuilder.SetReturnType(paramMapper.GetParameterType(methodToOverride.ReturnType));
            methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());

            int paramNum = 1;

            foreach (ParameterInfo pi in methodParameters)
            {
                methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder methodReturn = il.DeclareLocal(typeof(VirtualMethodInvocation));
            LocalBuilder inputs       = methodReturn;
            var          endlbl       = il.DefineLabel();


            // Create instance of VirtualMethodInvocation
            il.Emit(OpCodes.Ldarg_0); // target object

            // If we have a generic method, we want to make sure we're using the open constructed generic method
            // so when a closed generic version of the method is invoked the actual type parameters are used

            methodInfoForMethodHandle = methodToOverride.IsGenericMethodDefinition
                    ? methodToOverride.MakeGenericMethod(paramMapper.GenericMethodParameters)
                    : methodToOverride;

            if (!methodToOverride.IsGenericMethodDefinition)
            {
                statficfieldForMethodHandle =
                    typeBuilder.DefineField("methodBase" + methodToOverride.Name, typeof(MethodBase), FieldAttributes.Private | FieldAttributes.Static);
            }

            if (MethodHasReturnValue)
            {
                int index = porpertyIndex;
                il.Emit(OpCodes.Ldsfld, propsField);
                il.Emit(OpCodes.Ldc_I4, index);
                il.Emit(OpCodes.Ldelem_Ref);
                il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocationContructorGet);
            }
            else
            {
                //Emit reference to argument
                var methodParameter = methodParameters[0];
                EmitLoadArgument(il, 0);
                if (methodParameter.ParameterType.IsValueType || methodParameter.ParameterType.IsGenericParameter)
                {
                    il.Emit(OpCodes.Box, paramMapper.GetParameterType(methodParameter.ParameterType));
                }
                else if (methodParameter.ParameterType.IsByRef)
                {
                    Type elementType = paramMapper.GetElementType(methodParameter.ParameterType);
                    il.Emit(OpCodes.Ldobj, elementType);
                    if (elementType.IsValueType || elementType.IsGenericParameter)
                    {
                        il.Emit(OpCodes.Box, elementType);
                    }
                }

                int methodType = 1;
                il.Emit(OpCodes.Ldc_I4, methodType);
                int index = porpertyIndex;
                il.Emit(OpCodes.Ldsfld, propsField);
                il.Emit(OpCodes.Ldc_I4, index);
                il.Emit(OpCodes.Ldelem_Ref);
                il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocationContructorSet);
            }
            il.Emit(OpCodes.Stloc, inputs);


            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
            il.Emit(OpCodes.Ldloc, inputs);

            // Put delegate reference onto the stack
            il.Emit(OpCodes.Ldarg_0);

            MethodInfo invokeTarget = delegateMethod;

            if (delegateMethod.IsGenericMethod)
            {
                invokeTarget = delegateMethod.MakeGenericMethod(paramMapper.GenericMethodParameters);
            }

            il.Emit(OpCodes.Ldftn, invokeTarget);
            il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);

            // And call the pipeline
            il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);

            // handle return value
            if (MethodHasReturnValue)
            {
                //il.Emit(OpCodes.Ldloc, methodReturn);
                il.Emit(OpCodes.Ldfld, VirtualMethodInvocationMethods.GetReturnValue);
                if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
                {
                    il.Emit(OpCodes.Unbox_Any, paramMapper.GetReturnType());
                }
                else
                {
                    il.Emit(OpCodes.Castclass, paramMapper.GetReturnType());
                }
            }
            il.MarkLabel(endlbl);
            if (!MethodHasReturnValue)
            {
                il.Emit(OpCodes.Pop);
            }
            il.Emit(OpCodes.Ret);

            return(methodBuilder);
        }