猿问
下载APP

如何将String转换为其等效的LINQ表达式树?

这是原始问题的简化版本。


我有一个名为Person的类:


public class Person {

  public string Name { get; set; }

  public int Age { get; set; }

  public int Weight { get; set; }

  public DateTime FavouriteDay { get; set; }

}

......然后说一个例子:


var bob = new Person {

  Name = "Bob",

  Age = 30,

  Weight = 213,

  FavouriteDay = '1/1/2000'

}

我想在我最喜欢的文本编辑器中将以下内容写成字符串 ....


(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3

我想取这个字符串和我的对象实例并评估一个TRUE或FALSE - 即在对象实例上评估一个Func <Person,bool>。


这是我目前的想法:


在ANTLR中实现基本语法以支持基本比较和逻辑运算符。我想在这里复制Visual Basic优先级和一些功能集:http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx

让ANTLR从提供的字符串中创建合适的AST。

使用AST并使用Predicate Builder框架动态创建Func <Person,bool>

根据需要针对Person实例评估谓词

我的问题是我完全过度了吗?任何替代品?


编辑:选择解决方案

我决定使用Dynamic Linq Library,特别是LINQSamples中提供的Dynamic Query类。


代码如下:


using System;

using System.Linq.Expressions;

using System.Linq.Dynamic;


namespace ExpressionParser

{

  class Program

  {

    public class Person

    {

      public string Name { get; set; }

      public int Age { get; set; }

      public int Weight { get; set; }

      public DateTime FavouriteDay { get; set; }

    }


    static void Main()

    {

      const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";

      var p = Expression.Parameter(typeof(Person), "Person");

      var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, exp);

      var bob = new Person

      {

        Name = "Bob",

        Age = 30,

        Weight = 213,

        FavouriteDay = new DateTime(2000,1,1)

      };


      var result = e.Compile().DynamicInvoke(bob);

      Console.WriteLine(result);

      Console.ReadKey();

    }

  }

}

结果的类型为System.Boolean,在此实例中为TRUE。


非常感谢Marc Gravell。


包括System.Linq.Dynamic nuget包,文档在这里


哈士奇WWW
浏览 70回答 3
3回答

至尊宝的传说

请问动态LINQ库帮助吗?特别是,我在考虑作为一个Where条款。如有必要,将它放在列表/数组中只是为了调用.Where(string)它!即var people = new List<Person> { person };int match = people.Where(filter).Any();如果没有,编写一个解析器(Expression在引擎盖下使用)并不是很费力 - 我在圣诞节前的火车通勤中写了一个类似的(虽然我不认为我有源)。

潇潇雨雨

另一个这样的图书馆是逃离我做了一个比较快的动态LINQ的图书馆和回避率和回避率是为表达快10倍"(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)"这是如何使用Flee编写代码的。static void Main(string[] args){&nbsp; var context = new ExpressionContext();&nbsp; const string exp = @"(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3";&nbsp; context.Variables.DefineVariable("Person", typeof(Person));&nbsp; var e = context.CompileDynamic(exp);&nbsp; var bob = new Person&nbsp; {&nbsp; &nbsp; Name = "Bob",&nbsp; &nbsp; Age = 30,&nbsp; &nbsp; Weight = 213,&nbsp; &nbsp; FavouriteDay = new DateTime(2000, 1, 1)&nbsp; };&nbsp; context.Variables["Person"] = bob;&nbsp; var result = e.Evaluate();&nbsp; Console.WriteLine(result);&nbsp; Console.ReadKey();}

慕容4345310

void Main(){&nbsp; &nbsp; var testdata = new List<Ownr> {&nbsp; &nbsp; &nbsp; &nbsp; //new Ownr{Name = "abc", Qty = 20}, // uncomment this to see it getting filtered out&nbsp; &nbsp; &nbsp; &nbsp; new Ownr{Name = "abc", Qty = 2},&nbsp; &nbsp; &nbsp; &nbsp; new Ownr{Name = "abcd", Qty = 11},&nbsp; &nbsp; &nbsp; &nbsp; new Ownr{Name = "xyz", Qty = 40},&nbsp; &nbsp; &nbsp; &nbsp; new Ownr{Name = "ok", Qty = 5},&nbsp; &nbsp; };&nbsp; &nbsp; Expression<Func<Ownr, bool>> func = Extentions.strToFunc<Ownr>("Qty", "<=", "10");&nbsp; &nbsp; func = Extentions.strToFunc<Ownr>("Name", "==", "abc", func);&nbsp; &nbsp; var result = testdata.Where(func.ExpressionToFunc()).ToList();&nbsp; &nbsp; result.Dump();}public class Ownr{&nbsp; &nbsp; public string Name { get; set; }&nbsp; &nbsp; public int Qty { get; set; }}public static class Extentions{&nbsp; &nbsp; public static Expression<Func<T, bool>> strToFunc<T>(string propName, string opr, string value, Expression<Func<T, bool>> expr = null)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Expression<Func<T, bool>> func = null;&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var type = typeof(T);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var prop = type.GetProperty(propName);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ParameterExpression tpe = Expression.Parameter(typeof(T));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression left = Expression.Property(tpe, prop);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression right = Expression.Convert(ToExprConstant(prop, value), prop.PropertyType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(ApplyFilter(opr, left, right), tpe);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (expr != null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; innerExpr = innerExpr.And(expr);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; func = innerExpr;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ex)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ex.Dump();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return func;&nbsp; &nbsp; }&nbsp; &nbsp; private static Expression ToExprConstant(PropertyInfo prop, string value)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; object val = null;&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch (prop.Name)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "System.Guid":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = Guid.NewGuid();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; val = Convert.ChangeType(value, prop.PropertyType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ex)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ex.Dump();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return Expression.Constant(val);&nbsp; &nbsp; }&nbsp; &nbsp; private static BinaryExpression ApplyFilter(string opr, Expression left, Expression right)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; BinaryExpression InnerLambda = null;&nbsp; &nbsp; &nbsp; &nbsp; switch (opr)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "==":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "=":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.Equal(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "<":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.LessThan(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case ">":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.GreaterThan(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case ">=":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.GreaterThanOrEqual(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "<=":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.LessThanOrEqual(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "!=":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.NotEqual(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "&&":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.And(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case "||":&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; InnerLambda = Expression.Or(left, right);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return InnerLambda;&nbsp; &nbsp; }&nbsp; &nbsp; public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());&nbsp; &nbsp; &nbsp; &nbsp; return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);&nbsp; &nbsp; }&nbsp; &nbsp; public static Func<T, TResult> ExpressionToFunc<T, TResult>(this Expression<Func<T, TResult>> expr)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var res = expr.Compile();&nbsp; &nbsp; &nbsp; &nbsp; return res;&nbsp; &nbsp; }}LinqPad有这个Dump()方法
打开App,查看更多内容
随时随地看视频慕课网APP
我要回答