internal static Expression <Func <T, bool> > AndAlso <T>(this Expression <Func <T, bool> > exp1, Expression <Func <T, bool> > exp2) { if (exp1 == null) { return(exp2); } var parameter = Expression.Parameter(typeof(T)); var leftVisitor = new ReplaceVisitor(exp1.Parameters[0], parameter); var left = leftVisitor.Visit(exp1.Body); var rightVisitor = new ReplaceVisitor(exp2.Parameters[0], parameter); var right = rightVisitor.Visit(exp2.Body); return(Expression.Lambda <Func <T, bool> >( Expression.AndAlso(left, right), parameter)); }
/// <summary> /// Correlates all of the elements of an outer sequence with any matching elements of an inner sequence, based on matching keys. /// </summary> /// <typeparam name="TOuter">The type of the elements of the outer sequence.</typeparam> /// <typeparam name="TInner">The type of the elements of the inner sequence.</typeparam> /// <typeparam name="TKey">The type of the keys returned by the key selector functions.</typeparam> /// <typeparam name="TResult">The type of the result elements.</typeparam> /// <param name="outer">The outer sequence to join.</param> /// <param name="inner">The inner sequence to join.</param> /// <param name="outerKeySelector">A function to extract the join key from each element of the outer sequence.</param> /// <param name="innerKeySelector">A function to extract the join key from each element of the inner sequence.</param> /// <param name="resultSelector">A function to create a result element from two matching elements.</param> /// <returns>An <see cref="T:System.Collections.Generic.IEnumerable`1" /> that has elements of type <typeparamref name="TResult" /> that are obtained by performing an outer join on the input sequences.</returns> /// <remarks><para>All elements of <paramref name="outer" /> will be selected, even if there is no matching element in <paramref name="inner" />; in that case, the value that is passed as the second parameter to <paramref name="resultSelector" /> will be the default value for <typeparamref name="TInner" />.</para></remarks> public static IQueryable <TResult> LeftJoin <TOuter, TInner, TKey, TResult>(this IQueryable <TOuter> outer, IEnumerable <TInner> inner, Expression <Func <TOuter, TKey> > outerKeySelector, Expression <Func <TInner, TKey> > innerKeySelector, Expression <Func <TOuter, TInner, TResult> > resultSelector) { if (outer == null) { throw new ArgumentNullException(nameof(outer)); } if (inner == null) { throw new ArgumentNullException(nameof(inner)); } if (outerKeySelector == null) { throw new ArgumentNullException(nameof(outerKeySelector)); } if (innerKeySelector == null) { throw new ArgumentNullException(nameof(innerKeySelector)); } if (resultSelector == null) { throw new ArgumentNullException(nameof(resultSelector)); } // TODO: this var outerExample = new { o = default(TOuter), i = (IEnumerable <TInner>)null }; var type = outerExample.GetType(); var expression = Expression.Parameter(type, "a"); return(outer .GroupJoin(inner, outerKeySelector, innerKeySelector, (o, i) => new { o, i }) .SelectMany( x => x.i.DefaultIfEmpty(), Lambda( outerExample, default(TInner), default(TResult), ReplaceVisitor.Replace(resultSelector.Body, resultSelector.Parameters[0], Expression.Property(expression, type.GetProperty("o"))), new[] { expression, resultSelector.Parameters[1] } ) )); }
public static Expression <Func <T, bool> > CombineAnd <T>(this IEnumerable <Expression <Func <T, bool> > > filters) { if (!filters.Any()) { Expression <Func <T, bool> > alwaysTrue = x => true; return(alwaysTrue); } var firstFilter = filters.First(); var lastFilter = firstFilter; Expression <Func <T, bool> > result = null; foreach (var nextFilter in filters.Skip(1)) { var nextExpression = new ReplaceVisitor(lastFilter.Parameters[0], nextFilter.Parameters[0]).Visit(lastFilter.Body); result = Expression.Lambda <Func <T, bool> >(Expression.AndAlso(nextExpression, nextFilter.Body), nextFilter.Parameters); lastFilter = nextFilter; } return(result); }
public Expression Join(Expression beforeExpression) { if (_argumentIndex == -1) { throw new InvalidOperationException("cannot join not splitted expression"); } var arguments = new Expression[_afterExpression.Arguments.Count]; for (int i = 0; i < arguments.Length; i++) { arguments[i] = _afterExpression.Arguments[i]; } arguments[_argumentIndex] = beforeExpression; MethodCallExpression newAfterExpression = Expression.Call(_afterExpression.Object, _afterExpression.Method, arguments); var visitor = new ReplaceVisitor(_afterExpression, newAfterExpression); return(visitor.Visit(_source)); }
public void TestDecrement_Subtract1From1_MustReplaceWithDecrement() { Expression <Func <int, int> > sourceExpression = i => ((i - 2) + (i - 1)) + ((1 + i) - 1); var expectedExpression = Expression.Lambda(typeof(Func <int, int>), Expression.Add( Expression.Add( Expression.Subtract(_intParameter, Expression.Constant(2)), Expression.Decrement(_intParameter) ), Expression.Decrement( Expression.Increment(_intParameter) ) ), _intParameter); var actualExpression = new ReplaceVisitor().VisitAndConvert(sourceExpression, string.Empty); Assert.NotEqual(sourceExpression.ToString(), actualExpression.ToString()); //replace with real comparison Assert.Equal(expectedExpression.ToString(), actualExpression.ToString()); //replace with real comparison AssertExpressionsResults((Func <int, int>)expectedExpression.Compile(), (Func <int, int>)actualExpression.Compile(), testParameters); }
/// <summary> /// Remplaza todas las referencias a un elemento del WITH con un SqlTableRefRaw /// </summary> public static Expression SubqueryRawSubs(Expression subquery, ParameterExpression repParam) { if (subquery == null) { return(null); } //Sustituir todo param.X o param por el nombre: var ret = ReplaceVisitor.Replace(subquery, expr => { if (typeof(IFromListItemTarget).GetTypeInfo().IsAssignableFrom(expr.Type.GetTypeInfo())) { var selectInt = expr.Type.GetTypeInfo().ImplementedInterfaces.Concat(new[] { expr.Type }).Where(x => x.GetTypeInfo().IsGenericType&& x.GetGenericTypeDefinition() == typeof(IFromListItemTarget <>)).FirstOrDefault(); if (selectInt == null) { throw new ArgumentException("Debe de ser un IFromListItemTarget<T>"); } var selectType = selectInt.GetTypeInfo().GenericTypeArguments[0]; if (expr is MemberExpression mem && CompareExpr.ExprEquals(mem.Expression, repParam)) { return(RawSqlTableRefExpr(selectType, $"\"{mem.Member.Name}\"")); }
protected static Expression <Func <T, bool> > Combine <T>(Expression <Func <T, bool> > filter1, Expression <Func <T, bool> > filter2) { if (filter1 == null && filter2 == null) { return(null); } if (filter1 == null) { return(filter2); } if (filter2 == null) { return(filter1); } // combine two predicates: // need to rewrite one of the lambdas, swapping in the parameter from the other var rewrittenBody1 = new ReplaceVisitor(filter1.Parameters[0], filter2.Parameters[0]).Visit(filter1.Body); var newFilter = Expression.Lambda <Func <T, bool> >(Expression.AndAlso(rewrittenBody1, filter2.Body), filter2.Parameters); return(newFilter); }
public static IQueryable <T> InlineMatch <T>(this IQueryable <T> e) { var visitor = new ReplaceVisitor(); return(e.Provider.CreateQuery <T>(visitor.Visit(e.Expression))); }
public static T InlineMatch <T>(this T e) where T : Expression { var visitor = new ReplaceVisitor(); return((T)visitor.Visit(e)); }
/// <summary> /// Devuelve el resultado de aplicar una regla al niver superior de la expresión o la expresión original si la regla no se pudo aplicar a la expresión /// </summary> public static Expression GlobalApplyRule(Expression expr, RewriteRule rule, Func <Expression, Expression> visit) { if (rule.DebugName == "convertFromParam" || rule.DebugName == "fromParam") { ; } var parameters = rule.Find.Parameters; var pattBody = rule.Find.Body; PartialMatch partialMatch; try { partialMatch = GlobalMatch(expr, parameters, pattBody); } catch (Exception ex) { throw new ApplyRuleException("Error al obtener el match", rule.DebugName, expr, ex); } var match = PartialMatch.ToFullMatch(partialMatch, parameters); if (match == null) { return(expr); } if (rule.Condition != null && !rule.Condition(match, expr)) { return(expr); } //Sustituir la expresión: var ret = expr; var replaceLambda = rule.Replace; if (replaceLambda != null) { var subDic = replaceLambda.Parameters .Select((x, i) => (par: x, value: match.Args[i])) .ToDictionary(x => (Expression)x.par, x => x.value) ; Expression repRet; try { repRet = ReplaceVisitor.Replace(replaceLambda.Body, subDic, match.Types, x => false); } catch (Exception ex) { throw new ApplyRuleException("Error al reemplazar", rule.DebugName, expr, ex); } ret = repRet; } //Aplicar los transforms: { Expression nextRet; try { nextRet = ReplaceVisitor.Replace(ret, ex => { if (ex is MethodCallExpression call && call.Method.DeclaringType == typeof(RewriteSpecial) && call.Method.Name == nameof(RewriteSpecial.Transform)) { //Aplica el transform a la expresión: var arg = call.Arguments[0]; var func = ExprEval.EvalExpr <Func <Expression, Expression> >(call.Arguments[1]); var tResult = func.Value(arg); return(tResult); } return(ex); }); }
static IReadOnlyList<ExprAliasList> ExtractJoinAliasT(IFromListItem left, Expression leftParam, Expression rightParam, Expression onParam, Expression mapExprBody) { if (left == null) { return new[] { new ExprAliasList(new ExprRep[0], leftParam, onParam, null) }; } var subRet = ExtractJoinAliasTree(left); var leftOnParam = subRet[0].CurrParam; var currAliases = mapExprBody == null ? new ExpressionAlias[0] : ExtractAliases(mapExprBody); var ret = new List<ExprAliasList>(); //Si el left no tiene OnParam, debe de existir el lado izquierdo en el mapeo var existirLeft = leftOnParam == null; if (existirLeft && !currAliases.Any(x => x.Expr == leftParam)) { throw new ArgumentException($"El argumento '{leftParam}' debe de existir en el mapeo del ON del JOIN '{mapExprBody}' ya que el lado izquierdo es un from list que no esta nombrado"); } var mapAliases = currAliases.Select(x => new ExprRep( find: Expression.Property(onParam, x.Alias), rep: Expression.Property(onParam, x.Alias) )) .ToList(); //Encontrar el alias del left: var rightAlias = currAliases.Where(x => x.Expr == rightParam).Select(x => new ExprRep(x.Expr, Expression.Property(onParam, x.Alias))).FirstOrDefault(); if (rightAlias != null) { mapAliases.Add(rightAlias); } var currentExprAlias = new ExprAliasList(mapAliases, leftParam, onParam, null); ret.Add(currentExprAlias); var repList = currAliases.Select(x => new ExprRep( find: leftOnParam == null ? x.Expr : ReplaceVisitor.Replace(x.Expr, leftParam, leftOnParam), rep: Expression.Property(onParam, x.Alias) )) .ToList(); //Sustituir todos los subRet: var subRetSubs = subRet.Select(list => new ExprAliasList( items: list.Items.Select(item => new ExprRep( item.Find, ReplaceExprList(item.Rep, repList) )).ToList(), leftParam: list.LeftParam, currParam: list.CurrParam, leftOn: null )) .ToList() ; ret.AddRange(subRetSubs); //Agregar el alias del lado izquierdo: var leftAlias = currAliases.Where(x => x.Expr == leftParam).Select(x => new ExprRep(x.Expr, Expression.Property(onParam, x.Alias))).FirstOrDefault(); if (leftAlias != null) { var fromAlias = new ExprAliasList(new[] { leftAlias }, leftParam, onParam, null); ret.Add(fromAlias); } else { //Reemplazar el lado izquierdo de este JOIN con el ON del JOIN izquierdo leftAlias = new ExprRep(leftParam, leftOnParam); var mapAlRep = currAliases.Select(x => new ExprRep(x.Expr, ReplaceVisitor.Replace(x.Expr, leftParam, leftOnParam))).ToList(); var fromAlias = new ExprAliasList(mapAlRep, leftParam, onParam, null); ret.Add(fromAlias); } return ret; }
/// <summary> /// Applies an expression as argument to a lambda. /// </summary> /// <param name="lambda">A lambda expression with 1 parameter</param> /// <param name="ex">The expression to use as input for the lambda expression</param> /// <returns>The expanded body of the LambdaExpression.</returns> public static Expression ApplyTo(this LambdaExpression lambda, Expression ex) { var visitor = new ReplaceVisitor(lambda.Parameters[0], ex); return(visitor.Visit(lambda.Body)); }