/// <summary> /// Gets the delegate associated with the LambdaExpression. /// Either it uses cached MethodInfo and creates delegate from it, or it will generate /// completely new dynamic method, store it in a cache and use it to create the delegate. /// </summary> private static Delegate GetDelegateForInterpreter(InterpreterState state, LambdaExpression lambda) { MethodInfo method; if (!LambdaInvoker.TryGetGenericInvokeMethod(lambda.Parameters.Count, out method) || HasByRefParameter(lambda)) { return(GenerateDelegateForInterpreter(state, lambda)); } Type[] signature = GetSignature(lambda); method = method.MakeGenericMethod(signature); return(ReflectionUtils.CreateDelegate(method, lambda.Type, new LambdaInvoker(lambda, state))); }
/// <summary> /// The core of the interpreter, calling back onto itself via delegates. /// </summary> private static MethodInfo CreateDelegateForInterpreter(Type type) { Debug.Assert(type != typeof(Delegate) && typeof(Delegate).IsAssignableFrom(type)); // // Get the desired signature // MethodInfo invoke = type.GetMethod("Invoke"); ParameterInfo[] parameters = invoke.GetParameters(); string name = "Interpreted_" + Interlocked.Increment(ref _DelegateCounter); Type[] signature = CreateInterpreterSignature(parameters); DynamicILGen il = Snippets.Shared.CreateDynamicMethod(name, invoke.ReturnType, signature, false); // Collect all arguments received by the delegate into an array // and pass them to the Interpreter along with the LambdaInvoker // LambdaInvoker il.EmitLoadArg(0); int count = parameters.Length; // Create the array il.EmitInt(count); il.Emit(OpCodes.Newarr, typeof(object)); for (int i = 0; i < count; i++) { il.Emit(OpCodes.Dup); il.EmitInt(i); il.EmitLoadArg(i + 1); EmitExplicitCast(il, parameters[i].ParameterType, typeof(object)); il.EmitStoreElement(typeof(object)); } // Call back to interpreter il.EmitCall(LambdaInvoker.GetInvokeMethod()); // Cast back to the delegate return type EmitExplicitCast(il, typeof(object), invoke.ReturnType); // And return whatever the result was. il.Emit(OpCodes.Ret); // // We are done (for now), finish the MethodInfo // return(il.Finish()); }