public override void ProcessMethodCall(IOqlSyntaxContext callContext, MethodCallExpression methodCall) { if (methodCall.IsCalled(Skip)) { callContext.CallResult.Offset = (int)methodCall.GetArgument(1).GetValue(); return; } if (methodCall.IsCalled(Take)) { callContext.CallResult.Size = (int)methodCall.GetArgument(1).GetValue(); return; } if (methodCall.IsCalled(ElementAt)) { callContext.CallResult.Command = OqlCommandToken.ElementAt; callContext.CallResult.ElementIndex = (int)methodCall.GetArgument(1).GetValue(); return; } if (methodCall.IsCalled(ElementAtOrDefault)) { callContext.CallResult.ElementIndex = (int)methodCall.GetArgument(1).GetValue(); callContext.CallResult.Command = OqlCommandToken.ElementAt | OqlCommandToken.DefaultFlag; return; } ProcessNavigate(callContext, methodCall); }
public override void ProcessMethodCall(IOqlSyntaxContext callContext, MethodCallExpression methodCall) { if (methodCall.IsCalled(SkipWhile)) { AndAlso(Expression.Not(methodCall.GetArgument(1))); return; } AndAlso(methodCall.GetArgument(1)); OqlNavigationClause.ProcessNavigate(callContext, methodCall); }
private static void VerifyGetArguments(MethodCallExpression call) { var args = call.Arguments; Assert.Equal(args.Count, call.ArgumentCount); AssertExtensions.Throws <ArgumentOutOfRangeException>("index", () => call.GetArgument(-1)); AssertExtensions.Throws <ArgumentOutOfRangeException>("index", () => call.GetArgument(args.Count)); for (int i = 0; i != args.Count; ++i) { Assert.Same(args[i], call.GetArgument(i)); Assert.Equal(i, ((ConstantExpression)call.GetArgument(i)).Value); } }
protected override Expression VisitMethodCall(MethodCallExpression node) { if (node.GetArgument("ae") == parameter && (node.Method.Name == "Pattern" || node.Method.Name == "TryPattern")) { return(new AutomationPatternExpression(node.Method.GetGenericArguments()[0], node.Type)); } return(base.VisitMethodCall(node)); }
public override void ProcessMethodCall(IOqlSyntaxContext callContext, MethodCallExpression methodCall) { if (Distinct.Equals(methodCall)) { m_has_distinct = true; return; } m_select_expression = methodCall.GetArgument(1); callContext.CallResult.ResultType = methodCall.Type; if (m_select_expression.NodeType == ExpressionType.MemberInit || m_select_expression.NodeType == ExpressionType.New) { return; } if (methodCall.IsCalled(Min)) { visit_to_aggregate = (x, y) => callContext.AggregateFormatter.FormatMin(x, y); return; } if (methodCall.IsCalled(Max)) { visit_to_aggregate = (x, y) => callContext.AggregateFormatter.FormatMax(x, y); return; } if (methodCall.IsCalled("Average")) { visit_to_aggregate = (x, y) => callContext.AggregateFormatter.FormatAverage(x, y); return; } if (methodCall.IsCalled("Sum")) { visit_to_aggregate = (x, y) => callContext.AggregateFormatter.FormatSum(x, y); return; } if (methodCall.IsCalledOr(Count, LongCount)) { callContext.CallResult.Command = OqlCommandToken.Scalar; } visit_to_aggregate = null; }
public static void CheckCallFactoryInstanceN() { const int N = 4; ParameterExpression obj = Expression.Parameter(typeof(MS)); ConstantExpression[] args = Enumerable.Range(0, N).Select(i => Expression.Constant(i)).ToArray(); MethodCallExpression expr = Expression.Call(obj, typeof(MS).GetMethod("I" + N), args); if (!PlatformDetection.IsNetNative) // .Net Native blocks internal framework reflection. { Assert.Equal("InstanceMethodCallExpressionN", expr.GetType().Name); } Assert.Same(obj, expr.Object); Assert.Equal(N, expr.ArgumentCount); for (var i = 0; i < N; i++) { Assert.Same(args[i], expr.GetArgument(i)); } Collections.ObjectModel.ReadOnlyCollection <Expression> arguments = expr.Arguments; Assert.Same(arguments, expr.Arguments); Assert.Equal(N, arguments.Count); for (var i = 0; i < N; i++) { Assert.Same(args[i], arguments[i]); } MethodCallExpression updated = expr.Update(obj, arguments.ToList()); Assert.Same(expr, updated); var visited = (MethodCallExpression) new NopVisitor().Visit(expr); Assert.Same(expr, visited); var visitedObj = (MethodCallExpression) new VisitorObj().Visit(expr); Assert.NotSame(expr, visitedObj); Assert.NotSame(obj, visitedObj.Object); Assert.Same(arguments, visitedObj.Arguments); var visitedArgs = (MethodCallExpression) new VisitorArgs().Visit(expr); Assert.NotSame(expr, visitedArgs); Assert.Same(obj, visitedArgs.Object); Assert.NotSame(arguments, visitedArgs.Arguments); }
protected override Expression VisitMethodCall(MethodCallExpression node) { int start = 0; Expression ob = node.Object; if (node.Method.GetCustomAttribute(typeof(ExtensionAttribute)) != null) { start = 1; ob = node.GetArgument(0); } if (ob != null) { Visit(ob); Out('.'); } _criteriaBuilder.Clear(); Out(node.Method.Name); Out('('); for (int i = start, n = node.ArgumentCount(); i < n; i++) { if (i > start) { Out(", "); } Visit(node.GetArgument(i)); } Out(')'); if (string.Equals(node.Method.Name, "Where", StringComparison.InvariantCultureIgnoreCase)) { _queryCriteriaStr.Add(_criteriaBuilder.ToString()); _queryCriteriaExp.Add(node.GetArgument(1)); } _criteriaBuilder.Clear(); return(node); }
protected virtual void VisitOrderBy(IOqlExpressionVisitor visitor, MethodCallExpression methodCall) { visitor.Visit(methodCall.GetArgument(1)); if (methodCall.IsCalledOr(OrderBy, ThenBy)) { visitor.Query.AppendAsc(); return; } if (methodCall.IsCalledOr(OrderByDescending, ThenByDescending)) { visitor.Query.AppendDesc(); } }
protected override Expression VisitMethodCall(MethodCallExpression node) { try { string methodName = node.Method.Name.ToLower(); if (methodName.Equals("select")) { /* * The following means this, * * 01. Get arguments of select. * 02. Second argument is the expression that is invoked in select. * 03. If it is a new expression, it means it is possibly multiple project expression. * 04. But just in case look at the number of arguments to see if it is actually projecting * more than one attributes. */ UnaryExpression unaryExpression = (UnaryExpression)node.Arguments[1]; LambdaExpression lambdaExpression = (LambdaExpression)unaryExpression.Operand; if (lambdaExpression.Body is NewExpression newExpression) { multipleProjectionFlag = newExpression.ArgumentCount() > 1; } } functions[methodName]++; } catch (Exception e) { Logger.Log(e, Microsoft.Extensions.Logging.LogLevel.Warning); } if (node.Object != null) { Visit(node.Object); } for (int i = 0, n = node.ArgumentCount(); i < n; i++) { Visit(node.GetArgument(i)); } return(node); }
public static bool ExtractDefaultIfEmpty(ref Expression expression) { MethodCallExpression mce = expression as MethodCallExpression; if (mce == null || !mce.Method.IsGenericMethod) { return(false); } MethodInfo me = mce.Method.GetGenericMethodDefinition(); if (!ReflectionTools.MethodEqual(me, miDefaultIfEmptyE) && !ReflectionTools.MethodEqual(me, miDefaultIfEmptyQ)) { return(false); } expression = mce.GetArgument("source"); return(true); }
public override void ProcessMethodCall(IOqlSyntaxContext callContext, MethodCallExpression methodCall) { Expression x = methodCall.GetArgument(1); if (x.NodeType == ExpressionType.MemberInit) { m_change_set = new MemberInitChangeSet(x as MemberInitExpression); return; } object obj = x.GetValue(); if (obj is IDataChangeSet) { m_change_set = obj as IDataChangeSet; return; } m_change_set = new ObjectChangeSet(obj).ChangeAllProperties(); }
/* ******************************************************************************************************** * -------------------------------- VISITORS -------------------------------- * ******************************************************************************************************** */ protected override Expression VisitMethodCall(MethodCallExpression node) { Logger.Log("VisitMethodCall : " + node.ToString(), Microsoft.Extensions.Logging.LogLevel.Trace); object evalResult = EvaluateMethodAndCall(node); if (evalResult != null) { PadPossibleStringValueToWhere(evalResult) .Append(Space); /* * We don't need to visit further nodes. * Doing so will pad the arguments of the * method invoked which shouldn't be done. */ return(node); } if (node.Object != null) { Visit(node.Object); } for (int i = 0, n = node.ArgumentCount(); i < n; i++) { Visit(node.GetArgument(i)); } // Add an 'AND' for separating query data criteria. if (IsAndAble(node.Method.Name)) { if (whereBuilder.Length > 0) { whereBuilder.Append("AND").Append(Space); } } return(node); }
public static void CheckCallFactoryStaticN() { const int N = 6; ConstantExpression[] args = Enumerable.Range(0, N).Select(i => Expression.Constant(i)).ToArray(); MethodCallExpression expr = Expression.Call(typeof(MS).GetMethod("S" + N), args); Assert.Equal("MethodCallExpressionN", expr.GetType().Name); Assert.Equal(N, expr.ArgumentCount); for (var i = 0; i < N; i++) { Assert.Same(args[i], expr.GetArgument(i)); } Collections.ObjectModel.ReadOnlyCollection <Expression> arguments = expr.Arguments; Assert.Same(arguments, expr.Arguments); Assert.Equal(N, arguments.Count); for (var i = 0; i < N; i++) { Assert.Same(args[i], arguments[i]); } MethodCallExpression updated = expr.Update(null, arguments); Assert.Same(expr, updated); var visited = (MethodCallExpression) new NopVisitor().Visit(expr); Assert.Same(expr, visited); var visitedArgs = (MethodCallExpression) new VisitorArgs().Visit(expr); Assert.NotSame(expr, visitedArgs); Assert.Same(null, visitedArgs.Object); Assert.NotSame(arguments, visitedArgs.Arguments); }
protected override Expression VisitMethodCall(MethodCallExpression node) { Logger.Log("Visiting node : " + node.ToString(), Microsoft.Extensions.Logging.LogLevel.Trace); if (node.Object != null) { Visit(node.Object); } for (int i = 0, n = node.ArgumentCount(); i < n; i++) { Visit(node.GetArgument(i)); } if (node.Method.Name.Equals("Select")) { foreach (var arg in node.Arguments) { selectArguments.Add(arg); } } return(node); }
/// <summary> /// Gets the lambda expression given by the first argument. /// </summary> /// <param name="expression"></param> /// <param name="index"></param> /// <returns></returns> public static LambdaExpression GetLambdaArgument(this MethodCallExpression expression, int index) { return(expression.GetArgument(index).UnpackLambda()); }
/// <summary> /// Gets the lambda expression given by the first argument. /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="expression"></param> /// <param name="index"></param> /// <returns></returns> public static Expression <Func <T, TResult> > GetLambdaArgument <T, TResult>(this MethodCallExpression expression, int index) { return(expression.GetArgument(index).UnpackLambda <T, TResult>()); }
protected override Expression VisitMethodCall(MethodCallExpression m) { if (m.Method.DeclaringType == typeof(Queryable) || m.Method.DeclaringType == typeof(Enumerable) || m.Method.DeclaringType == typeof(EnumerableUniqueExtensions)) { switch (m.Method.Name) { case "Where": return(this.BindWhere(m.Type, m.GetArgument("source"), m.GetArgument("predicate").StripQuotes())); case "Select": return(this.BindSelect(m.Type, m.GetArgument("source"), m.GetArgument("selector").StripQuotes())); case "SelectMany": if (m.Arguments.Count == 2) { return(this.BindSelectMany(m.Type, m.GetArgument("source"), m.GetArgument("selector").StripQuotes(), null)); } else { return(this.BindSelectMany(m.Type, m.GetArgument("source"), m.GetArgument("collectionSelector").StripQuotes(), m.TryGetArgument("resultSelector").StripQuotes())); } case "Join": return(this.BindJoin( m.Type, m.GetArgument("outer"), m.GetArgument("inner"), m.GetArgument("outerKeySelector").StripQuotes(), m.GetArgument("innerKeySelector").StripQuotes(), m.GetArgument("resultSelector").StripQuotes())); case "OrderBy": return(this.BindOrderBy(m.Type, m.GetArgument("source"), m.GetArgument("keySelector").StripQuotes(), OrderType.Ascending)); case "OrderByDescending": return(this.BindOrderBy(m.Type, m.GetArgument("source"), m.GetArgument("keySelector").StripQuotes(), OrderType.Descending)); case "ThenBy": return(this.BindThenBy(m.GetArgument("source"), m.GetArgument("keySelector").StripQuotes(), OrderType.Ascending)); case "ThenByDescending": return(this.BindThenBy(m.GetArgument("source"), m.GetArgument("keySelector").StripQuotes(), OrderType.Descending)); case "GroupBy": return(this.BindGroupBy(m.Type, m.GetArgument("source"), m.GetArgument("keySelector").StripQuotes(), m.GetArgument("elementSelector").StripQuotes())); case "Count": return(this.BindCount(m.Type, m.GetArgument("source"))); case "DefaultIfEmpty": return(Visit(m.GetArgument("source"))); case "Any": return(this.BindAny(m.Type, m.GetArgument("source"))); case "All": return(this.BindAll(m.Type, m.GetArgument("source"), m.GetArgument("predicate").StripQuotes())); case "Contains": return(this.BindContains(m.Type, m.GetArgument("source"), m.TryGetArgument("item") ?? m.GetArgument("value"))); case "Sum": case "Min": case "Max": case "Average": return(this.BindAggregate(m.Type, m.Method.Name.ToEnum <AggregateSqlFunction>(), m.GetArgument("source"), m.TryGetArgument("selector").StripQuotes())); case "First": case "FirstOrDefault": case "Single": case "SingleOrDefault": return(BindUniqueRow(m.Type, m.Method.Name.ToEnum <UniqueFunction>(), m.GetArgument("source"), m.TryGetArgument("predicate").StripQuotes())); case "FirstEx": case "SingleEx": case "SingleOrDefaultEx": return(BindUniqueRow(m.Type, m.Method.Name.RemoveEnd(2).ToEnum <UniqueFunction>(), m.GetArgument("collection"), m.TryGetArgument("predicate").StripQuotes())); case "Distinct": return(BindDistinct(m.Type, m.GetArgument("source"))); case "Take": return(BindTake(m.Type, m.GetArgument("source"), m.GetArgument("count"))); case "Skip": return(BindSkip(m.Type, m.GetArgument("source"), m.GetArgument("count"))); } } if (m.Method.Name == "Mixin" && m.Method.GetParameters().Length == 0) { var obj = Visit(m.Object); if (obj is MetaExpression me && me.Meta is CleanMeta) { CleanMeta cm = (CleanMeta)me.Meta; var mixinType = m.Method.GetGenericArguments().Single(); return(new MetaExpression(mixinType, new CleanMeta(null, cm.PropertyRoutes.Select(a => a.Add(mixinType)).ToArray()))); } } if (m.Method.DeclaringType == typeof(LinqHints) || m.Method.DeclaringType == typeof(LinqHintEntities)) { return(Visit(m.Arguments[0])); } if (m.Method.DeclaringType == typeof(StringExtensions) && m.Method.Name == nameof(StringExtensions.Etc)) { return(Visit(m.Arguments[0])); } if (m.Method.DeclaringType == typeof(Lite) && m.Method.Name == "ToLite") { return(MakeCleanMeta(m.Type, Visit(m.Arguments[0]))); } if (m.Method.DeclaringType == typeof(Math) && (m.Method.Name == "Abs" || m.Method.Name == "Ceiling" || m.Method.Name == "Floor" || m.Method.Name == "Round" || m.Method.Name == "Truncate")) { return(MakeCleanMeta(m.Type, Visit(m.Arguments[0]))); } if (m.Method.Name == "ToString" && m.Object != null && typeof(IEntity).IsAssignableFrom(m.Object.Type)) { return(Visit(Expression.Property(m.Object, piToStringProperty))); } if (m.Object != null) { var a = this.Visit(m.Object); var list = this.Visit(m.Arguments); return(MakeDirtyMeta(m.Type, null, list.PreAnd(a).ToArray())); } else { var list = this.Visit(m.Arguments); return(MakeDirtyMeta(m.Type, null, list.ToArray())); } }
protected override Expression VisitMethodCall(MethodCallExpression m) { Type decType = m.Method.DeclaringType; if (m.Method.IsGenericMethod && (decType == typeof(Queryable) || decType == typeof(Enumerable))) { bool query = decType == typeof(Queryable); Type[] paramTypes = m.Method.GetGenericArguments(); MethodInfo mi = m.Method.GetGenericMethodDefinition(); //IE<IGrouping<K, S>> GroupBy<S, K>(this IE<S> source, Func<S, K> keySelector); // GroupBy(col, a=>func(a)) -> GroupBy(col, a=>func(a), a=>a) if (ReflectionTools.MethodEqual(mi, miGroupBySE) || ReflectionTools.MethodEqual(mi, miGroupBySQ)) { var source = Visit(m.GetArgument("source")); var keySelector = (LambdaExpression)Visit(m.GetArgument("keySelector").StripQuotes()); MethodInfo miG = (query ? miGroupByNQ : miGroupByNE) .MakeGenericMethod(paramTypes[0], paramTypes[1], paramTypes[0]); ParameterExpression p = Expression.Parameter(paramTypes[0], "p" + i++); return(Expression.Call(miG, source, keySelector, Expression.Lambda(p, p))); } //IE<R> GroupBy<S, K, R>(this IE<S> source, Func<S, K> keySelector, Func<K, IE<S>, R> resultSelector); // GroupBy(col, a=>f1(a), a=>f2(a), (a,B)=>f3(a,B)) -> GroupBy(col, a=>f1(a), a=>f2(a)).Select(g=>=>f3(g.Key,g)) if (ReflectionTools.MethodEqual(mi, miGroupBySRE) || ReflectionTools.MethodEqual(mi, miGroupBySRQ)) { var source = Visit(m.GetArgument("source")); var keySelector = (LambdaExpression)Visit(m.GetArgument("keySelector").StripQuotes()); var resultSelector = (LambdaExpression)Visit(m.GetArgument("resultSelector").StripQuotes()); Type groupingType = typeof(IGrouping <,>).MakeGenericType(paramTypes[1], paramTypes[0]); MethodInfo miG = (query ? miGroupByNQ : miGroupByNE) .MakeGenericMethod(paramTypes[0], paramTypes[1], paramTypes[0]); MethodInfo miS = (query ? miSelectQ : miSelectE) .MakeGenericMethod(groupingType, paramTypes[2]); ParameterExpression g = Expression.Parameter(groupingType, "g" + i++); LambdaExpression newResult = Expression.Lambda( Replacer.Replace(Replacer.Replace(resultSelector.Body, resultSelector.Parameters[0], Expression.MakeMemberAccess(g, groupingType.GetProperty("Key"))), resultSelector.Parameters[1], g), g); ParameterExpression p = Expression.Parameter(paramTypes[0], "p" + i++); return (Expression.Call(miS, Expression.Call(miG, source, keySelector, Expression.Lambda(p, p)), newResult)); } //IE<R> GroupBy<S, K, E, R>(this IE<S> source, Func<S, K> keySelector, Func<S, E> elementSelector, Func<K, IE<E>, R> resultSelector) // GroupBy(col, a=>f1(a), a=>f2(a), (k,B)=>f(k,B)) -> GroupBy(col, a=>f1(a), a=>f2(a)).Select(g=>f3(g.Key,g)) if (ReflectionTools.MethodEqual(mi, miGroupByNRE) || ReflectionTools.MethodEqual(mi, miGroupByNRQ)) { var source = Visit(m.GetArgument("source")); var keySelector = (LambdaExpression)Visit(m.GetArgument("keySelector").StripQuotes()); var elementSelector = (LambdaExpression)Visit(m.GetArgument("elementSelector").StripQuotes()); var resultSelector = (LambdaExpression)Visit(m.GetArgument("resultSelector").StripQuotes()); Type groupingType = typeof(IGrouping <,>).MakeGenericType(paramTypes[1], paramTypes[2]); MethodInfo miG = (query ? miGroupByNQ : miGroupByNE) .MakeGenericMethod(paramTypes[0], paramTypes[1], paramTypes[2]); MethodInfo miS = (query ? miSelectQ : miSelectE) .MakeGenericMethod(groupingType, paramTypes[3]); ParameterExpression g = Expression.Parameter(groupingType, "g" + i++); LambdaExpression newResult = Expression.Lambda( Replacer.Replace(Replacer.Replace(resultSelector.Body, resultSelector.Parameters[0], Expression.MakeMemberAccess(g, groupingType.GetProperty("Key"))), resultSelector.Parameters[1], g), g); return (Expression.Call(miS, Expression.Call(miG, source, keySelector, elementSelector), newResult)); } //IE<R> GroupJoin<O, I, K, R>(this IE<O> outer, IE<I> inner, Func<O, K> outerKeySelector, Func<I, K> innerKeySelector, Func<O, IE<I>, R> resultSelector) // GroupJoin(outer, inner, o=>f1(o), i=>f2 //(i), (o, gI)=>f3(o,gI)) --> // Join(outer, GroupBy(inner, i=>f2(i), i=>i) , o=>f1(o), g=>g.Key, (o,g)=>f2(o, g)) if (ReflectionTools.MethodEqual(mi, miGroupJoinE) || ReflectionTools.MethodEqual(mi, miGroupJoinQ)) { Type tO = paramTypes[0], tI = paramTypes[1], tK = paramTypes[2], tR = paramTypes[3]; var outer = Visit(m.GetArgument("outer")); var inner = Visit(m.GetArgument("inner")); bool hasDefaultIfEmpty = ExtractDefaultIfEmpty(ref inner); var outerKeySelector = (LambdaExpression)Visit(m.GetArgument("outerKeySelector").StripQuotes()); var innerKeySelector = (LambdaExpression)Visit(m.GetArgument("innerKeySelector").StripQuotes()); var resultSelector = (LambdaExpression)Visit(m.GetArgument("resultSelector").StripQuotes()); Type groupingType = typeof(IGrouping <,>).MakeGenericType(tK, tI); MethodInfo miG = (query ? miGroupByNQ : miGroupByNQ) .MakeGenericMethod(tI, tK, tI); ParameterExpression p = Expression.Parameter(tI, "p" + i++); Expression group = Expression.Call(miG, inner, innerKeySelector, Expression.Lambda(p, p)); if (hasDefaultIfEmpty) { var method = (query ? miDefaultIfEmptyQ : miDefaultIfEmptyE) .MakeGenericMethod(groupingType); group = Expression.Call(method, group); } //IQueryable<R> Join<TOuter, TInner, TKey, R>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, R>> resultSelector); MethodInfo mij = (query ? miJoinQ : miJoinE) .MakeGenericMethod(tO, groupingType, tK, tR); ParameterExpression g = Expression.Parameter(groupingType, "g" + i++); LambdaExpression newResult = Expression.Lambda( Replacer.Replace(resultSelector.Body, resultSelector.Parameters[1], g), resultSelector.Parameters[0], g); return (Expression.Call(mij, outer, group, outerKeySelector, Expression.Lambda(Expression.MakeMemberAccess(g, groupingType.GetProperty("Key")), g), newResult)); } if (ReflectionTools.MethodEqual(mi, miCastE) || ReflectionTools.MethodEqual(mi, miCastQ)) { var source = Visit(m.GetArgument("source")); Type elemType = source.Type.ElementType(); ParameterExpression pe = Expression.Parameter(elemType); var lambdaCast = Expression.Lambda(Expression.Convert(pe, paramTypes[0]), pe); return(Expression.Call((query ? miSelectQ : miSelectE).MakeGenericMethod(elemType, paramTypes[0]), source, lambdaCast)); } if (ReflectionTools.MethodEqual(mi, miOfTypeE) || ReflectionTools.MethodEqual(mi, miOfTypeQ)) { var source = Visit(m.GetArgument("source")); Type elemType = source.Type.ElementType(); ParameterExpression pe = Expression.Parameter(elemType); var lambdaIs = Expression.Lambda(Expression.TypeIs(pe, paramTypes[0]), pe); var lambdaCast = Expression.Lambda(Expression.Convert(pe, paramTypes[0]), pe); var where = Expression.Call((query ? miWhereQ : miWhereE).MakeGenericMethod(elemType), source, lambdaIs); return(Expression.Call((query ? miSelectQ : miSelectE).MakeGenericMethod(elemType, paramTypes[0]), where, lambdaCast)); } if (mi.Name.Contains("Last")) { var source = Visit(m.GetArgument("source")); var predicate = (LambdaExpression)Visit(m.TryGetArgument("predicate").StripQuotes()); Expression reverse = Expression.Call((query ? miReverseQ : miReverseE).MakeGenericMethod(paramTypes[0]), source); if (predicate != null) { reverse = Expression.Call((query ? miWhereQ : miWhereE).MakeGenericMethod(paramTypes[0]), reverse, predicate); } MethodInfo mEqFirst = query ? mi.Name.Contains("OrDefault") ? miFirstOrDefaultQ : miFirstQ : mi.Name.Contains("OrDefault") ? miFirstOrDefaultE : miFirstE; return(Expression.Call(mEqFirst.MakeGenericMethod(paramTypes[0]), reverse)); } if (ReflectionTools.MethodEqual(mi, miElementAtE) || ReflectionTools.MethodEqual(mi, miElementAtOrDefaultE) || ReflectionTools.MethodEqual(mi, miElementAtQ) || ReflectionTools.MethodEqual(mi, miElementAtOrDefaultQ)) { bool def = ReflectionTools.MethodEqual(mi, miElementAtOrDefaultE) || ReflectionTools.MethodEqual(mi, miElementAtOrDefaultQ); var source = Visit(m.GetArgument("source")); var index = Visit(m.GetArgument("index")); MethodInfo first = (def ? (query ? miFirstOrDefaultQ : miFirstOrDefaultE) : (query ? miFirstQ : miFirstE)).MakeGenericMethod(paramTypes[0]); MethodInfo skip = (query ? miSkipQ : miSkipE).MakeGenericMethod(paramTypes[0]); return(Visit(Expression.Call(first, Expression.Call(skip, source, index)))); } if (ReflectionTools.MethodEqual(mi, miSkipE) || ReflectionTools.MethodEqual(mi, miSkipQ)) { var source = Visit(m.GetArgument("source")); var count = Visit(m.GetArgument("count")); ParameterExpression pi = Expression.Parameter(typeof(int), "i"); ParameterExpression pa = Expression.Parameter(paramTypes[0], "a"); Expression lambda = Expression.Lambda(Expression.LessThanOrEqual(count, pi), pa, pi); MethodInfo miWhereIndex = (query ? miWhereIndexQ : miWhereIndexE).MakeGenericMethod(paramTypes[0]); return(Expression.Call(miWhereIndex, source, lambda)); } if (ReflectionTools.MethodEqual(mi, miTakeE) || ReflectionTools.MethodEqual(mi, miTakeQ)) { if (m.GetArgument("source") is MethodCallExpression m2) { var mi2 = (((MethodCallExpression)m2).Method).GetGenericMethodDefinition(); if (ReflectionTools.MethodEqual(mi2, miSkipE) || ReflectionTools.MethodEqual(mi2, miSkipQ)) { var source = Visit(m2.GetArgument("source")); var skip = Visit(m2.GetArgument("count")); var take = Visit(m.GetArgument("count")); ParameterExpression pi = Expression.Parameter(typeof(int), "i"); ParameterExpression pa = Expression.Parameter(paramTypes[0], "a"); Expression lambda = Expression.Lambda( Expression.And( Expression.LessThanOrEqual(skip, pi), Expression.LessThan(pi, Expression.Add(skip, take)) ), pa, pi); MethodInfo miWhereIndex = (query ? miWhereIndexQ : miWhereIndexE).MakeGenericMethod(paramTypes[0]); return(Expression.Call(miWhereIndex, source, lambda)); } } } } if (m.Method.DeclaringType == typeof(Tuple) && m.Method.Name == "Create") { var types = m.Arguments.Select(e => e.Type).ToArray(); if (types.Length < 8) { return(Expression.New(m.Method.ReturnType.GetConstructor(types), m.Arguments.ToArray())); } else { Type lastType = types[7]; types[7] = typeof(Tuple <>).MakeGenericType(lastType); return(Expression.New(m.Method.ReturnType.GetConstructor(types), m.Arguments.Take(7).And( Expression.New(types[7].GetConstructor(new[] { lastType }), m.Arguments[7])).ToArray())); } } if (m.Method.DeclaringType == typeof(EnumerableExtensions) && m.Method.IsGenericMethod) { MethodInfo mi = m.Method.GetGenericMethodDefinition(); if (ReflectionTools.MethodEqual(mi, miToStringSeparator)) { var type = m.Method.GetGenericArguments().SingleEx(); if (type != typeof(string)) { var source = Visit(m.GetArgument("source")); var p = Expression.Parameter(type); var toString = Visit(Expression.Lambda(Expression.Call(p, miToString), p)); var separator = Visit(m.GetArgument("separator")); return(Expression.Call(miToStringSeparator.MakeGenericMethod(typeof(string)), Expression.Call(miSelectE.MakeGenericMethod(type, typeof(string)), source, toString), separator)); } } else if (ReflectionTools.MethodEqual(mi, miToStringSeparatorE) || ReflectionTools.MethodEqual(mi, miToStringSeparatorQ)) { var type = m.Method.GetGenericArguments().SingleEx(); bool isQuery = ReflectionTools.MethodEqual(mi, miToStringSeparatorQ); var source = Visit(m.GetArgument("source")); var toString = (LambdaExpression)Visit(m.GetArgument("toString").StripQuotes()); var separator = Visit(m.GetArgument("separator")); return(Expression.Call(miToStringSeparator.MakeGenericMethod(typeof(string)), Expression.Call((isQuery ? miSelectQ : miSelectE).MakeGenericMethod(type, typeof(string)), source, toString), separator)); } } return(base.VisitMethodCall(m)); }