Exemple #1
0
        /// <summary>
        /// Creates a method that invokes the target interface method
        /// </summary>
        /// <param name="mIlGen">Method body IL generator</param>
        /// <param name="method">Interface method information</param>
        private static void GenerateInvokeMethod(ILGenerator mIlGen, MethodInfo method)
        {
            // ReSharper disable AssignNullToNotNullAttribute
            // --- Obtain method parameters
            var parameters = method.GetParameters();

            // --- Generate a local variable for output arguments
            var outputArgs = mIlGen.DeclareLocal(typeof(List <MethodArgument>));

            mIlGen.Emit(OpCodes.Newobj, typeof(List <MethodArgument>).GetConstructor(Type.EmptyTypes));
            mIlGen.Emit(OpCodes.Stloc_S, outputArgs);

            // --- Rest counters
            var inArgIndex  = 0;
            var outArgIndex = 0;

            // --- Iterate throug parameters
            var descriptors = new ParameterDescriptor[parameters.Length];

            for (var index = 0; index < parameters.Length; index++)
            {
                var parameter = parameters[index];
                descriptors[index] = new ParameterDescriptor
                {
                    Name          = parameter.Name,
                    Type          = parameter.ParameterType,
                    LocalVariable = null,
                    InArgIndex    = -1,
                    OutArgIndex   = -1
                };

                // --- Generate reference and output variables
                if (parameter.ParameterType.IsByRef || parameter.IsOut)
                {
                    // --- This argument must be an output argument
                    descriptors[index].OutArgIndex = outArgIndex++;

                    // --- Generate a local variable
                    var paramType = GetNonReferencedType(parameter.ParameterType);
                    descriptors[index].Type          = paramType;
                    descriptors[index].LocalVariable = mIlGen.DeclareLocal(paramType);
                    if (!parameter.IsOut)
                    {
                        // --- Argument passed by reference
                        descriptors[index].InArgIndex = inArgIndex++;

                        // --- Initialize the local variable with the corresponding input argument
                        PushArgumentValueByIndex(mIlGen, descriptors[index].InArgIndex, paramType);
                        mIlGen.Emit(OpCodes.Stloc_S, descriptors[index].LocalVariable);
                    }
                }
                else
                {
                    // --- Simple input argument
                    descriptors[index].InArgIndex = inArgIndex++;
                }
            }

            // --- Its time to call the method on the target
            mIlGen.Emit(OpCodes.Ldarg_1); // --- Push target

            // --- Push parameters to the stack
            for (var index = 0; index < parameters.Length; index++)
            {
                var parameter = parameters[index];
                if (parameter.ParameterType.IsByRef || parameter.IsOut)
                {
                    mIlGen.Emit(OpCodes.Ldloca_S, descriptors[index].LocalVariable);
                }
                else
                {
                    PushArgumentValueByIndex(mIlGen, descriptors[index].InArgIndex, parameter.ParameterType);
                }
            }

            // --- Invoke the method
            mIlGen.Emit(OpCodes.Callvirt, method);
            LocalBuilder returnValue = null;

            // --- Store the result, if there is any
            if (method.ReturnType != typeof(void))
            {
                returnValue = mIlGen.DeclareLocal(method.ReturnType);
                mIlGen.Emit(OpCodes.Stloc_S, returnValue);
            }

            // --- Extract output arguments
            foreach (var paramDescr in descriptors.Where(p => p.OutArgIndex >= 0))
            {
                mIlGen.Emit(OpCodes.Ldloc_S, outputArgs);
                mIlGen.Emit(OpCodes.Ldstr, paramDescr.Name);
                mIlGen.Emit(OpCodes.Ldloc_S, paramDescr.LocalVariable);
                if (paramDescr.Type.IsValueType)
                {
                    mIlGen.Emit(OpCodes.Box, paramDescr.Type);
                }
                mIlGen.Emit(OpCodes.Newobj, typeof(MethodArgument)
                            .GetConstructor(new [] { typeof(string), typeof(object) }));
                mIlGen.Emit(OpCodes.Callvirt, typeof(List <MethodArgument>).GetMethod("Add"));
            }

            // --- Create the response object
            if (returnValue == null)
            {
                // --- No return value
                mIlGen.Emit(OpCodes.Ldc_I4_0);
                mIlGen.Emit(OpCodes.Ldnull);
            }
            else
            {
                // --- There is a return value
                mIlGen.Emit(OpCodes.Ldc_I4_1);
                mIlGen.Emit(OpCodes.Ldloc_S, returnValue);
                if (method.ReturnType.IsValueType)
                {
                    // --- Do not forget to box value types
                    mIlGen.Emit(OpCodes.Box, method.ReturnType);
                }
            }
            mIlGen.Emit(OpCodes.Ldloc_S, outputArgs);
            mIlGen.Emit(OpCodes.Newobj, typeof(MethodResultDescriptor).GetConstructor(
                            new[] { typeof(bool), typeof(object), typeof(List <MethodArgument>) }));
            mIlGen.Emit(OpCodes.Ret);
            // ReSharper restore AssignNullToNotNullAttribute
        }