如何将字符串转换为其等效的 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
以下是我目前的想法:
- 在 ANTLR 中实现基本语法以支持基本的比较和逻辑运算符。 我正在考虑在这里复制 Visual Basic 优先级和一些功能集: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- 让 ANTLR 从提供的字符串创建合适的 AST。
- 遍历 AST 并使用 Predicate Builder 框架动态创建 Func
。 - 根据需要评估 Person 实例的谓词
我的问题是我是否完全过度烘焙了这个? 有替代方案吗?
编辑:选择的解决方案
我决定使用动态 Linq 库,特别是 LINQSamples 中提供的动态查询类。
代码如下:
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。
非常感谢马克·格拉维尔。
包含 System.Linq.Dynamic nuget 包、文档 此处
This is a simplified version of the original problem.
I have a class called Person:
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
public DateTime FavouriteDay { get; set; }
}
...and lets say an instance:
var bob = new Person {
Name = "Bob",
Age = 30,
Weight = 213,
FavouriteDay = '1/1/2000'
}
I would like to write the following as a string in my favourite text editor....
(Person.Age > 3 AND Person.Weight > 50) OR Person.Age < 3
I would like to take this string and my object instance and evaluate a TRUE or FALSE - i.e. evaluating a Func<Person, bool> on the object instance.
Here are my current thoughts:
- Implement a basic grammar in ANTLR to support basic Comparison and Logical Operators. I am thinking of copying the Visual Basic precedence and some of the featureset here: http://msdn.microsoft.com/en-us/library/fw84t893(VS.80).aspx
- Have ANTLR create a suitable AST from a provided string.
- Walk the AST and use the Predicate Builder framework to dynamically create the Func<Person, bool>
- Evaluate the predicate against an instance of Person as required
My question is have I totally overbaked this? any alternatives?
EDIT: Chosen Solution
I decided to use the Dynamic Linq Library, specifically the Dynamic Query class provided in the LINQSamples.
Code below:
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();
}
}
}
Result is of type System.Boolean, and in this instance is TRUE.
Many thanks to Marc Gravell.
Include System.Linq.Dynamic nuget package, documentation here
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
动态 linq 库 这里有帮助吗? 特别是,我正在考虑作为
Where
子句。 如有必要,请将其放入列表/数组中,以便对其调用.Where(string)
! 也就是说,如果没有,编写一个解析器(在引擎盖下使用
Expression
)并不是一件很费力的事情 - 我在圣诞节前的火车通勤中写了一个类似的(尽管我不认为我有源代码) ...Would the dynamic linq library help here? In particular, I'm thinking as a
Where
clause. If necessary, put it inside a list/array just to call.Where(string)
on it! i.e.If not, writing a parser (using
Expression
under the hood) isn't hugely taxing - I wrote one similar (although I don't think I have the source) in my train commute just before xmas...另一个这样的库是 Flee
我对 动态 Linq 库 和 Flee< /a> 和 Flee 对于表达式
“(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)”的速度快了 10 倍
这是您如何使用 Flee 编写代码的方法。
Another such library is Flee
I did a quick comparison of Dynamic Linq Library and Flee and Flee was 10 times faster for the expression
"(Name == \"Johan\" AND Salary > 500) OR (Name != \"Johan\" AND Salary > 300)"
This how you can write your code using Flee.
LinqPad 具有
Dump()
方法LinqPad has the
Dump()
method您可以查看 DLR。 它允许您在 .NET 2.0 应用程序内评估和执行脚本。 这是 IronRuby 的示例:
当然,这种技术基于运行时评估,并且无法在编译时验证代码。
You might take a look at the DLR. It allows you to evaluate and execute scripts inside .NET 2.0 application. Here's a sample with IronRuby:
Of course this technique is based on runtime evaluation and code cannot be verified at compile time.
下面是一个基于 Scala DSL 的解析器组合器的示例,用于解析和评估算术表达式。
所提供的算术表达式的等效表达式树或解析树将是 Parser[List[String]] 类型。
更多详细信息请访问以下链接:
http ://nicolaecaralicea.blogspot.ca/2013/04/scala-dsl-for-parsing-and-evaluating-of.html
Here is an example of a Scala DSL based parser combinator for parsing and evaluating of arithmetic expressions.
The equivalent expression tree or parse tree of the provided arithmetic expression would be of the Parser[List[String]] type.
More details are at the following link:
http://nicolaecaralicea.blogspot.ca/2013/04/scala-dsl-for-parsing-and-evaluating-of.html
除了动态 Linq 库(它构建强类型表达式并需要强类型变量)之外,我可能会推荐一个更好的替代方案: NReco .LambdaParser(开源)。 它在运行时对齐所有类型并执行所有调用,其行为类似于动态语言:
In addition to Dynamic Linq Library (which builds strongly typed expression and requires strongly typed variables) I may recommend a better alternative: NReco.LambdaParser (open source). It aligns all types and performs all invocations at runtime and behaves like dynamic language: