尽管.NET社区热切盼望Roslyn的正式版本,但工作还是要继续。所以今天我们来介绍另一个编译器服务——Expression Evaluator。虽然其他编译器服务都试图尽可能地全面,但它却独辟蹊径。
\InfoQ:你说C# Expression Evaluator是一个轻量级库,是什么让它成为一个轻量级的库?什么样的库又是重量级的呢?
\\\Repert Avery:Expression Evaluator的目标是计算表达式,就此而言我认为它是轻量级的,因为它很小(不到1M),是自包含的,不依赖于其他非核心库(除了Antlr),并且功能独特。我认为Roslyn是重量级的,因为它需要很多库的支持。当然,每个库都有自己的目标,很多Roslyn能做的事Expression Evaluator可能永远都做不到,如编译整个程序集。但就计算小的表达式来说,我相信Expression Evaluator已经做得非常好了。
\
InfoQ:Antlr是什么?你为什么会将它包含在库里?
\\\Rupert: Antlr(“又一个语言识别工具”的缩写)是一个最初用Java编写的库,可以根据特殊的语法(文法)来构建复杂的解析器代码。它就像是一个用于语言解析的加强版的正则表达式。你可以编写某种语言的语法规则,Antlr会为你生成代码。
\在使用Antlr之前我自己编写了这个解析器,它能做一个表达式解析器所需要的所有基础的工作。我能够支持“a + b.method(c,d[e] == f)”这样的表达式。它的规则十分简单。但当我想支持Lambda语法时,一切就变得复杂起来。例如表达式“(a,b) =\u0026gt; a==b”,(a,b)应该先解析为参数列表,然后再解析Lambda符号=\u0026gt;之后的所有内容(可能为块表达式),这难倒了我。我需要进行一些回溯并抛弃生成的token。我那手写的解析器显然无法完成这个任务。
\Antlr让一切变得简单。它能让我关注于编写处理各种语言的代码,而不用操心用于解析的代码。
\必须为我正使用的语法文件的作者点赞。我在https://antlrcsharp.codeplex.com/找到了这个十分完整的C# 4.0语法文件,我所要做的,就是对每种情况编写代码,来生成适当的表达式。
\
InfoQ:文档中提到了LINQ表达式树。能详细说说你是如何使用的吗?
\\\Rupert:LINQ表达式能将解析好的表达式存储为某种数据结构。与其自己构建数据结构,不如使用.NET Framework提供的结构。表达式树还有一个优势是可以编译为.NET函数。当表达式被编译为实际的.NET CLR代码后,就可以通过调用该函数来计算表达式。预编译代码的好处是速度的提升。其他不使用LINQ表达式的库,在计算表达式时,会遍历等价的表达式树,通过执行代码来模拟正在执行的代码,这是一笔巨大的开销。
\比如这样的表达式:
\x == a + b
\它的表达式树可能为:
\根:
\节点类型:Equals
\左子节点: 参数表达式x
\右子节点: (加法表达式)
\加法表达式:
\节点类型:Add
\左子结点:参数表达式a
\右子节点:参数表达式b
\这在C#中可以写成:
\\Expression.Equals(Expression.Parameter('x'), Expression.Add(Expression.Parameter('a'), Expression.Parameter('b'));
Expression Evaluator接下来(使用Antlr)解析该表达式,生成适当的表达式树。构建完表达式树之后,可以通过LINQ将其编译为函数。使用这个库的应用程序可以执行这个函数,就像它已经在第一时间被编译过了一样。被编译为函数之后,表达式树就不再需要了,不过我们可以用它来分析表达式,我相信肯定会有人想要枚举表达式所用到的变量或属性。由于表达式树记录了每个表达式的类型,因此是可以通过这种方式提取这些信息的。
\
InfoQ:假设我们在编写一个客户端-服务器系统。我们需要从客户端向服务器发送搜索条件(如where子句)。你会对这样的系统使用这个库吗?如果会,那么将是什么样子的?
\\\Rupert:在这种场景下,如果模型复杂,或查询逻辑复杂,并且客户端可以使用字符串自由地定义查询,那么Expression Evaluator就非常有用。Expression Evaluator将工作于服务器端,解析查询并转换为编译后的代码。
\我不清楚你所说的“将是什么样子”是指什么,不过使用了Expression Evaluator的Web应用程序可以让用户使用代码来定义查询,给用户提供一个可访问的参数集合,用户可以用C#代码来编写查询,并将原封不动地发送给服务器进行解析和编译。
\如果查询需要大量条件代码并且需要考虑性能,这将是Expression Evaluator发挥最大作用的时候。与其在查询中使用大量分支条件,不如基于必要的条件构建一个字符串表达式,并将其编译为可在查询中运行的委托。
\使用LINQ表达式树并没有将其局限于只能为LINQ表达式构建动态where子句。Expression Evaluator还可用于数据绑定。此时,用一个XML文件存储布局,并使用特性和特殊的符号来标记该文本用于数据绑定,而不是纯文本。XML元素模仿HTML,双花括号的符号模仿AngularJS。结果就是一个很像HTML/AngularJS的布局和模板引擎,输出的是PowerPoint幻灯片。布局引擎为开发者提供了HTML的灵活性,而Expression Evaluator允许数据绑定到布局上并控制布局,在PowerPoint中生成丰富的报告。
\
Expression Evaluator在CodePlex上以Simplified BSD协议开源。
\原文链接:Expression Evaluator: A Lightweight C# Compiler Service