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);
        }
Exemplo n.º 2
0
        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);
        }