public void LambdaExpression() { var tparameter = ODataExpression.Parameter("t"); var cparameter = ODataExpression.Parameter("c"); var l1 = new ODataLambdaExpression { Body = ODataExpression.PropertyOrField("Items", cparameter), Parameters = new[] { cparameter } }; var aparameter = ODataExpression.Parameter("a"); var bparameter = ODataExpression.Parameter("b"); var l2 = new ODataLambdaExpression { Body = ODataExpression.Add(ODataExpression.PropertyOrField("Id", aparameter), ODataExpression.PropertyOrField("Id", bparameter)), Parameters = new[] { aparameter, bparameter } }; var method = new ODataMethodCallExpression { Context = ODataExpression.PropertyOrField("Customers", tparameter), MethodName = "SelectMany", Arguments = new ODataExpression[] { l1, l2 } }; var expression = new ODataLambdaExpression { Body = method, Parameters = new [] { tparameter } }; //t => t.Customers.SelectMany(c => c.Customers, (a, b) => (a.Id + b.Id)) //t => t.Customers.SelectMany(c => c.Customers, (a, b) => (a.Id + b.Id)) var methods = typeof(Queryable).GetMethods() .Where(x => x.Name == "SelectMany" && x.GetParameters().Length == 3) .ToArray(); foreach (var methodInfo in methods) { // var arguments = methodInfo.GetGenericArguments(); // var parameter = DynamicExpression.Parameter(arguments[0], "t"); // var dd = DynamicExpression.Property(parameter, "Customers"); // } //var expr = Linq.Linq.Expr<Customer, IEnumerable<int>>(t => t.Customers.SelectMany(c => c.Items, (a, b) => a.Id + b.Id)); //var translator = new QueryTranslator(); //var d = translator.Invoke<Customer, IEnumerable<int>>(expression); }
private ODataExpression ParseIdentifier(bool minus, ODataParameterExpression parameter, ODataExpression parent = null, IDictionary <string, ODataParameterExpression> lambdaParameters = null) { for (_current++; _current < _source.Length; _current++) { var c = _source[_current]; if (!IsIdentifierChar(c)) { break; } } var name = _source.Substring(_offset, _current - _offset); var lastOffset = _offset; _offset = _current; switch (name) { case "INF": return(ODataExpression.Constant(double.PositiveInfinity)); case "-INF": return(ODataExpression.Constant(double.NegativeInfinity)); case "Nan": return(ODataExpression.Constant(double.NaN)); case "true": return(ODataExpression.Constant(true)); case "false": return(ODataExpression.Constant(false)); case "null": return(ODataExpression.Constant(null, typeof(object))); case "-": { return(new ODataUnaryExpression(ExpressionType.Negate)); } default: if (minus) { // Reset the offset. _offset = lastOffset + 1; return(new ODataUnaryExpression(ExpressionType.Negate)); } break; } if (_offset < _source.Length) { switch (_source[_offset]) { case '\'': { StringType stringType; switch (name) { case "X": stringType = StringType.Binary; break; case "binary": stringType = StringType.Binary; break; case "datetime": stringType = StringType.DateTime; break; case "guid": stringType = StringType.Guid; break; case "time": stringType = StringType.Time; break; case "datetimeoffset": stringType = StringType.DateTimeOffset; break; default: stringType = StringType.None; break; } if (stringType != StringType.None && _source[_offset] == '\'') { var content = ParseString(); return(ParseSpecialString((string)content.Value, stringType)); } if (stringType == StringType.None) { var content = ParseString(); return(ParceValue(name, (string)content.Value)); } break; } case ':': { _offset++; var depth = 0; var p = ODataExpression.Parameter(name); var lp = new Dictionary <string, ODataParameterExpression>(lambdaParameters ?? new Dictionary <string, ODataParameterExpression>()); lp[p.Name] = p; var tokens = new List <ODataExpression>(); while (true) { var token = GetNext(parameter, null, lp); if (token == null) { break; } if (token.NodeType == ExpressionType.Default) { var syntaxExpressionToken = (ODataSyntaxExpression)token; if (syntaxExpressionToken.Syntax == ',') { _offset--; break; } if (syntaxExpressionToken.Syntax == '(') { depth++; } if (syntaxExpressionToken.Syntax == ')') { if (depth == 0) { _offset--; break; } depth--; } } tokens.Add(token); } var body = CreateExpression(ConvertToRpn(tokens)); var lambdaExpression = new ODataLambdaExpression { Parameters = new[] { p }, Body = body }; return(lambdaExpression); } case '/': { _offset++; if (lambdaParameters != null && lambdaParameters.ContainsKey(name) && parent == null) { return(ParseIdentifier(false, parameter, lambdaParameters[name], lambdaParameters)); } if (name.StartsWith("Ase.") && parent != null && name.Substring(4) == parent.ToString().Replace(parameter.ToString() + ".", "")) { return(ParseIdentifier(false, parameter, parent, lambdaParameters)); } return(ParseIdentifier(false, parameter, ODataExpression.PropertyOrField(name, parent ?? parameter), lambdaParameters)); } case '(': //Если следующий элемент скобка, значит это функция { var depth = 0; var comma = false; var arguments = new List <ODataExpression>(); var temp = new List <ODataExpression>(); while (true) { var token = GetNext(parameter, null, lambdaParameters); if (token == null) { break; } var syntax = token as ODataSyntaxExpression; if (syntax != null && syntax.Syntax == ',') { if (temp.Any()) { var tokens = ConvertToRpn(temp.ToArray()); var expression = CreateExpression(tokens); arguments.Add(expression); temp = new List <ODataExpression>(); comma = true; } else { throw new Exception("extra comma"); } } else { if (syntax != null && syntax.Syntax == '(') { if (comma) { throw new Exception("extra comma"); } depth++; } if (syntax != null && syntax.Syntax == ')') { if (comma) { throw new Exception("extra comma"); } depth--; } if (syntax == null || !(syntax.Syntax == '(' && depth == 1) && !(syntax.Syntax == ')' && depth == 0)) { temp.Add(token); } comma = false; if (depth == 0) { if (temp.Any()) { var tokens = ConvertToRpn(temp.ToArray()); var expression = CreateExpression(tokens); arguments.Add(expression); } break; } } } if (depth != 0) { throw new Exception("Parenthesis mismatch"); } var methodCallExpression = new ODataMethodCallExpression { Context = parent, MethodName = name, Arguments = arguments.ToArray() }; if (_offset < _source.Length && _source[_offset] == '/') { _current++; _offset = _offset + 1; return(ParseIdentifier(false, parameter, methodCallExpression, lambdaParameters)); } return(methodCallExpression); } } } if (name.IsOperator()) { var expressionType = name.GetExpressionType(); if (name.IsUnaryOperator()) { return(ODataExpression.MakeUnary(expressionType, null)); } if (name.IsArithmeticOperator() || name.IsLogicalOperator()) { return(ODataExpression.MakeBinary(expressionType, null, null)); } } if (parent == null && lambdaParameters != null && lambdaParameters.ContainsKey(name)) { return(lambdaParameters[name]); } if (name.Contains(".")) { var type = GetType(name); return(ODataExpression.Constant(type)); } return(ODataExpression.PropertyOrField(name, parent ?? parameter)); }
private Expression VisitMethodCall(ODataMethodCallExpression node) { var functionName = node.MethodName.ToLowerInvariant(); switch (functionName) { case "contains": { var right = Visit(node.Arguments[0]); var left = Visit(node.Arguments[1]); return(Expression.Call(right, MethodProvider.ContainsMethod, new[] { left })); } case "endswith": { var right = Visit(node.Arguments[1]); var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.EndsWithMethod, new[] { right })); } case "startswith": { var right = Visit(node.Arguments[1]); var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.StartsWithMethod, new[] { right })); } case "length": { var left = Visit(node.Arguments[0]); return(Expression.Property(left, MethodProvider.LengthProperty)); } case "indexof": { var right = Visit(node.Arguments[1]); var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.IndexOfMethod, new[] { right })); } case "substring": { if (node.Arguments.Length == 3) { return(Expression.Call(Visit(node.Arguments[0]), MethodProvider.SubstringMethodWithTwoArg, new[] { Visit(node.Arguments[1]), Visit(node.Arguments[2]) })); } if (node.Arguments.Length == 2) { return(Expression.Call(Visit(node.Arguments[0]), MethodProvider.SubstringMethodWithOneArg, new[] { Visit(node.Arguments[1]) })); } throw new NotSupportedException(); //Нет перегрузки для данного метода } case "tolower": { var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.ToLowerMethod)); } case "toupper": { var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.ToUpperMethod)); } case "trim": { var left = Visit(node.Arguments[0]); return(Expression.Call(left, MethodProvider.TrimMethod)); } case "hour": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.HourProperty)); } case "minute": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.MinuteProperty)); } case "second": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.SecondProperty)); } case "day": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.DayProperty)); } case "month": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.MonthProperty)); } case "year": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Property(left, MethodProvider.YearProperty)); } case "round": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Call(left.Type == typeof(double) ? MethodProvider.DoubleRoundMethod : MethodProvider.DecimalRoundMethod, new[] { left })); } case "floor": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Call(left.Type == typeof(double) ? MethodProvider.DoubleFloorMethod : MethodProvider.DecimalFloorMethod, new[] { left })); } case "ceiling": { var left = Visit(node.Arguments[0]); if (left.Type.IsNullableType()) { left = Expression.Property(left, "Value"); } return(Expression.Call(left.Type == typeof(double) ? MethodProvider.DoubleCeilingMethod : MethodProvider.DecimalCeilingMethod, new[] { left })); } case "concat": { var right = Visit(node.Arguments[1]); var left = Visit(node.Arguments[0]); return(Expression.Add(left, right, MethodProvider.ConcatMethod)); } case "replace": { return(Expression.Call(Visit(node.Arguments[0]), MethodProvider.ReplaceMethod, new[] { Visit(node.Arguments[1]), Visit(node.Arguments[2]) })); } case "sum": case "average": { var context = Visit(node.Context); var genericArguments = context.Type.GetTypeGenericArguments(); var arguments = node.Arguments.Select(argument => argument.NodeType == ExpressionType.Lambda ? VisitLambda((ODataLambdaExpression)argument, genericArguments[0]) : Visit(argument)).ToList(); arguments.Insert(0, context); var type = context.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable); return(Expression.Call(type, functionName, arguments.Count == 1 ? Type.EmptyTypes : genericArguments, arguments.ToArray())); } case "min": case "max": case "selectmany": { var context = Visit(node.Context); var genericArguments = context.Type.GetGenericArguments(); var arguments = node.Arguments.Select(argument => argument.NodeType == ExpressionType.Lambda ? VisitLambda((ODataLambdaExpression)argument, genericArguments[0]) : Visit(argument)).ToList(); arguments.Insert(0, context); var type = context.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable); var expr = ExpressionMethodBinder.Bind(type, functionName, null, arguments.ToArray()); return(expr); } case "groupby": case "orderby": case "orderbydescending": case "thenby": case "thenbydescending": case "select": { var context = Visit(node.Context); var genericArguments = context.Type.GetTypeGenericArguments().ToList(); var lambda = (LambdaExpression)VisitLambda((ODataLambdaExpression)node.Arguments[0], genericArguments[0]); genericArguments.Add(lambda.ReturnType); var type = context.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable); return(Expression.Call(type, functionName, genericArguments.ToArray(), new[] { context, lambda })); } case "any": case "all": case "first": case "where": case "take": case "skip": case "distinct": case "last": case "lastordefault": case "single": case "singleordefault": case "defaultifempty": case "count": case "longcount": case "firstordefault": { var context = Visit(node.Context); var genericArguments = context.Type.GetTypeGenericArguments(); var arguments = node.Arguments.Select(argument => argument.NodeType == ExpressionType.Lambda ? VisitLambda((ODataLambdaExpression)argument, genericArguments[0]) : Visit(argument)).ToList(); arguments.Insert(0, context); var type = context.Type.IsIQueryable() ? typeof(Queryable) : typeof(Enumerable); return(Expression.Call(type, functionName, genericArguments, arguments.ToArray())); } case "isof": { //ParameterExpression parameter = null; Expression genericParameter = null; object typeName = null; if (node.Arguments.Length == 1) { genericParameter = _parameters.Select(x => x.Value).FirstOrDefault(); typeName = ((ConstantExpression)Visit(node.Arguments[0])).Value; } if (node.Arguments.Length == 2) { var arguments = node.Arguments.Select(Visit).ToArray(); genericParameter = arguments[0]; typeName = ((ConstantExpression)arguments[1]).Value; } if (genericParameter != null) { var type = typeName is Type ? (Type)typeName : null; if (type == null && KnownAssembly != null) { type = KnownAssembly.GetType((string)typeName); } return(Expression.TypeIs(genericParameter, type)); } throw new NotSupportedException(node.DebugView()); } case "cast": { if (node.Arguments.Length == 1) { var parameter = _parameters.Select(x => x.Value).FirstOrDefault(); if (parameter != null) { var type = (Type)((ConstantExpression)Visit(node.Arguments[0])).Value; return(Expression.TypeAs(parameter, type)); } } if (node.Arguments.Length == 2) { var arguments = node.Arguments.Select(Visit).ToArray(); return(Expression.TypeAs(arguments[0], (Type)((ConstantExpression)arguments[1]).Value)); } throw new NotSupportedException(node.DebugView()); } case "substringof": { var right = Visit(node.Arguments[1]); var left = Visit(node.Arguments[0]); return(Expression.Call(right, MethodProvider.ContainsMethod, new[] { left })); } default: { if (node.Context != null) { var context = Visit(node.Context); var arguments = node.Arguments.Select(Visit).ToList(); var expr = ExpressionMethodBinder.Bind(context.Type, functionName, context, arguments.ToArray()); if (expr == null) { throw new Exception(String.Format("Can't find a method: {0}", node.DebugView())); } return(expr); } if (MethodProvider.UserFunctions.ContainsKey(node.MethodName)) { var arguments = node.Arguments.Select(Visit).ToArray(); var methodExpression = ExpressionMethodBinder.Bind( MethodProvider.UserFunctions[node.MethodName], node.MethodName, null, arguments); if (methodExpression == null) { throw new Exception(String.Format("Can't find a method: {0}", node.DebugView())); } return(methodExpression); } throw new NotSupportedException(String.Format("Can't find a method: {0}", node.DebugView())); } } }