/// <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)); }
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)); }
/// <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); }