protected override Expression VisitMethodCall(MethodCallExpression m) { if (m.Method.Name == "Project" && m.Method.DeclaringType == typeof(Extensions)) { Expression projectionExpression = m.Arguments[0]; LambdaExpression projectionLambda = ExtractLambda(projectionExpression); // Visit the lambda, essentially extracting the lambda's expression tree Expression visitedMethodCall = Visit(projectionLambda.Body); // Revisit the lambda's expression tree, replacing the lambda's parameter with the actual expression that results in the same return value var parameterMap = new Dictionary<ParameterExpression, Expression>(); int lambdaParameterArgumentIndex = 1; foreach (var parameter in projectionLambda.Parameters) { parameterMap.Add(parameter, m.Arguments[lambdaParameterArgumentIndex++]); } visitedMethodCall = new ParameterRebinder(parameterMap).Visit(visitedMethodCall); return visitedMethodCall; } return base.VisitMethodCall(m); }
protected override Expression VisitMethodCall(MethodCallExpression m) { Expression visitedMethodCall = null; if (m.Method.Name == "Select") { _selectStack.Push(m); } if (m.Method.Name == "Project" && m.Method.DeclaringType == typeof(Extensions)) { // Project() is expected to be invoked on an Expression<Func<In, Out>>, // the expression can be contained in a local variable, a field, retrived from a method // or any other expression tree as long as it can be compiled and executed to return a proper lambda ParameterExpression selectParameter = GetSelectParameter(_selectStack.Peek()); LambdaExpression innerLambda = GetInnerLambda(m.Arguments[0], selectParameter.Type, m.Method.ReturnType); // By returning the visited body of the lambda we ommit the call to Project() // and the tree producing the selector lambda: visitedMethodCall = Visit(innerLambda.Body); // The lambda takes a parameter, this parameter must be replaced by the parameter provided for the seelct lambda // Rebind parameter: var map = new Dictionary <ParameterExpression, ParameterExpression>() { { innerLambda.Parameters[0], selectParameter } }; visitedMethodCall = new ParameterRebinder(map).Visit(visitedMethodCall); } if (visitedMethodCall == null) { visitedMethodCall = base.VisitMethodCall(m); } if (m.Method.Name == "Select") { _selectStack.Pop(); } return(visitedMethodCall); }