private Expression[] GetAllArgs(Expression[] args, Reference targetField) { var allArgs = new Expression[args.Length + 1]; args.CopyTo(allArgs, 1); allArgs[0] = new ConvertExpression(targetType, targetField.ToExpression()); return allArgs; }
protected void CreateIInvocationInvokeOnTarget( ClassEmitter targetTypeEmitter, NestedClassEmitter nested, ParameterInfo[] parameters, FieldReference targetField, MethodInfo callbackMethod) { const MethodAttributes methodAtts = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual; MethodEmitter method = nested.CreateMethod ("InvokeMethodOnTarget", methodAtts, typeof (void)); Expression[] args = new Expression[parameters.Length]; // Idea: instead of grab parameters one by one // we should grab an array Hashtable byRefArguments = new Hashtable(); for(int i = 0; i < parameters.Length; i++) { ParameterInfo param = parameters[i]; Type paramType = param.ParameterType; if (HasGenericParameters(paramType)) { paramType = paramType.GetGenericTypeDefinition().MakeGenericType(nested.GetGenericArgumentsFor(paramType)); } else if (paramType.IsGenericParameter) { paramType = nested.GetGenericArgument(paramType.Name); } if (paramType.IsByRef) { LocalReference localReference = method.CodeBuilder.DeclareLocal(paramType.GetElementType()); method.CodeBuilder.AddStatement( new AssignStatement(localReference, new ConvertExpression(paramType.GetElementType(), new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod( "GetArgumentValue"), new LiteralIntExpression(i))))); ByRefReference byRefReference = new ByRefReference(localReference); args[i] = new ReferenceExpression(byRefReference); byRefArguments[i] = localReference; } else { args[i] = new ConvertExpression(paramType, new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("GetArgumentValue"), new LiteralIntExpression(i))); } } MethodInvocationExpression baseMethodInvExp; if (callbackMethod.IsGenericMethod) { callbackMethod = callbackMethod.MakeGenericMethod(nested.GetGenericArgumentsFor(callbackMethod)); } baseMethodInvExp = new MethodInvocationExpression(targetField, callbackMethod, args); baseMethodInvExp.VirtualCall = true; LocalReference ret_local = null; if (callbackMethod.ReturnType != typeof(void)) { if (callbackMethod.ReturnType.IsGenericParameter) { ret_local = method.CodeBuilder.DeclareLocal(nested.GetGenericArgument(callbackMethod.ReturnType.Name)); } else if (HasGenericParameters(callbackMethod.ReturnType)) { ret_local = method.CodeBuilder.DeclareLocal( callbackMethod.ReturnType.GetGenericTypeDefinition().MakeGenericType( nested.GetGenericArgumentsFor(callbackMethod.ReturnType))); } else { ret_local = method.CodeBuilder.DeclareLocal(callbackMethod.ReturnType); } method.CodeBuilder.AddStatement(new AssignStatement(ret_local, baseMethodInvExp)); } else { method.CodeBuilder.AddStatement(new ExpressionStatement(baseMethodInvExp)); } foreach(DictionaryEntry byRefArgument in byRefArguments) { int index = (int) byRefArgument.Key; LocalReference localReference = (LocalReference) byRefArgument.Value; method.CodeBuilder.AddStatement( new ExpressionStatement( new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("SetArgumentValue"), new LiteralIntExpression(index), new ConvertExpression(typeof(object), localReference.Type, new ReferenceExpression(localReference))) )); } if (callbackMethod.ReturnType != typeof(void)) { MethodInvocationExpression setRetVal = new MethodInvocationExpression(SelfReference.Self, typeof(AbstractInvocation).GetMethod("set_ReturnValue"), new ConvertExpression(typeof(object), ret_local.Type, ret_local.ToExpression())); method.CodeBuilder.AddStatement(new ExpressionStatement(setRetVal)); } method.CodeBuilder.AddStatement(new ReturnStatement()); }