/// <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 }