Replaces an expression with another one.
Inheritance: System.Linq.Expressions.ExpressionVisitor
Ejemplo n.º 1
0
        /// <summary>
        /// Returns <see cref="expression"/> with instances of <see cref="toReplace"/>
        /// replaced by <see cref="replaceWith"/>.
        /// </summary>
        public static Expression Replace(
            Expression expression, Expression toReplace, Expression replaceWith)
        {
            var replacer = new ExpressionReplacer(toReplace, replaceWith);

            return(replacer.Visit(expression));
        }
Ejemplo n.º 2
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var methodName    = node.Method.Name;
            var declaringType = node.Method.DeclaringType;

            if (node.Object == m_pageParameter)
            {
                if (declaringType == typeof(object))
                {
                    throw new InvalidOperationException(
                              string.Format("The method '{0}' is not supported.", methodName));
                }

                return(Expression.Call(
                           m_pageDataParameter,
                           PageDataGetDataMethod.MakeGenericMethod(node.Method.ReturnType.GetGenericArguments().Last()),
                           Expression.Constant(methodName)));
            }

            // ToEnumerable, ToList or FirstOrDefault
            var toEnumerableOrToList = (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(WikiQueryResult <,>));
            var first = declaringType == typeof(WikiQueryFirstExtension);

            if (toEnumerableOrToList || first)
            {
                var instance       = first ? node.Arguments.Single() : node.Object;
                var propExpression = ExpressionFinder.Single <MethodCallExpression>(
                    instance, e => e.Object == m_pageParameter && e.Method.DeclaringType == m_pageParameter.Type);

                var propName = propExpression.Method.Name;

                if (m_parameters.ContainsKey(propName))
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  "Each prop module can be use at most once in a single query, but you used the module '{0}' more than once.",
                                  propName));
                }

                var createQueryParametersMethod = typeof(QueryParameters).GetMethod("Create")
                                                  .MakeGenericMethod(propExpression.Type.GetGenericArguments().Last());

                var queryObject = Activator.CreateInstance(
                    propExpression.Type, new[] { null, createQueryParametersMethod.Invoke(null, null) });

                var withQueryObject = ExpressionReplacer.Replace(
                    instance, propExpression, Expression.Constant(queryObject));

                var processedQueryObject =
                    Expression.Lambda <Func <IWikiQueryResult> >(withQueryObject).Compile().Invoke();

                var parameter = new PropQueryParameters(propName);

                parameter.CopyFrom(processedQueryObject.Parameters);

                if (first)
                {
                    parameter = parameter.WithOnlyFirst();
                }

                m_parameters.Add(propName, parameter);

                m_canUsePage = true;

                var obj = Visit(instance);

                m_canUsePage = false;

                if (methodName == "ToEnumerable")
                {
                    return(obj);
                }

                if (first)
                {
                    methodName = "SingleOrDefault";
                }

                return(Expression.Call(
                           typeof(Enumerable), methodName, new[] { obj.Type.GetGenericArguments().Single() }, obj));
            }
            // one of the LINQ methods
            if (BaseTypes(declaringType).Contains(typeof(WikiQueryResult <,>)))
            {
                var obj = Visit(node.Object);

                if (methodName != "Select")
                {
                    return(obj);
                }

                var argument         = ((UnaryExpression)node.Arguments.Single()).Operand;
                var genericArguments = argument.Type.GetGenericArguments();

                return(Expression.Call(
                           typeof(Enumerable), methodName, new[] { genericArguments[0], genericArguments[1] }, obj, argument));
            }

            return(base.VisitMethodCall(node));
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Returns <see cref="expression"/> with instances of <see cref="toReplace"/>
 /// replaced by <see cref="replaceWith"/>.
 /// </summary>
 public static Expression Replace(
     Expression expression, Expression toReplace, Expression replaceWith)
 {
     var replacer = new ExpressionReplacer(toReplace, replaceWith);
     return replacer.Visit(expression);
 }