BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Expression Evaluator:一个轻量级的C#编译器服务

| 作者 Jonathan Allen 关注 595 他的粉丝 ,译者 姚琪琳 关注 0 他的粉丝 发布于 2014年5月9日. 估计阅读时间: 7 分钟 | QCon上海2018 关注大数据平台技术选型、搭建、系统迁移和优化的经验。

尽管.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) => a==b”,(a,b)应该先解析为参数列表,然后再解析Lambda符号=>之后的所有内容(可能为块表达式),这难倒了我。我需要进行一些回溯并抛弃生成的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

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT