天天看点

使用 Roslyn 编译器服务

.net core和 .net 4.6中 的c# 6/7 中的编译器roslyn 一个重要的特性就是"compiler as a service",简单的讲,就是就是将编译器开放为一种可在代码中调用的服务, 通常在工作流引擎 或是规则引擎中都需要一项功能是计算表达式, 在没有roslyn 之前我通常借助于antlr [antlr(“又一个语言识别工具”的缩写)是一个最初用java编写的库,可以根据特殊的语法(文法)来构建复杂的解析器代码。它就像是一个用于语言解析的加强版的正则表达式。你可以编写某种语言的语法规则,antlr会为你生成代码],基于antlr 有一个轻量级的c#编译器服务expression evaluator 。

要在自己的代码中使用roslyn 执行c#脚本,首先进行如下几步准备工作。

1、通过nuget 安装microsoft.codeanalysis.csharp.scripting

2、在代码中增加如下命名空间的引用。

经典的helloworld

首先还是以经典的hello world来开始介绍如何执行脚本吧。

从上述代码中可以看出,执行一个脚本还是比较简单的, 可以通过microsoft.codeanalysis.csharp.scripting.csharpscript.runasync() 函数执行自己的脚本了,如果我们要获取脚本的返回值,也是很容易的。

在会话中执行脚本

很多时候,我们无法一次执行所有的脚本,而是像shell中那样输入一句执行一句的。假如我们执行如下代码

得到的并不是我们想要的结果6,而是一个异常:

使用 Roslyn 编译器服务

究其原因,是因为csharpscript.runasync 函数每次都是在一个单独的上下文中执行的,并不会和前面的语句产生关联。如果我们要在csharpscript.create()函数创建一个脚本,通过函数continuewith 组成一个完整的脚本运行。正确方式如下:

在脚本和程序中共享数据

我们在执行脚本时,除了获取脚本的输出外,许多时候需要设置脚本的输入,要设置输入的方式也有许多。最直接的方式拼接脚本但这么做的效率和可维护性是十分差的。另外也可以通过传统的ipc通信机制——文件、socket等方式,这种方式一来比较麻烦,二来对于复杂的对象来说,还牵涉到序列化,也是非常不便。

roslyn提供了一个更为简单有效的解决办法:在会话中传入一个宿主对象,会话中的脚本程序也能访问宿主对象的各成员变量。

通过对象bar 把握的输入传给表达式,然后表达式就可以计算结果,这个就是我们在工作流引擎里面要的表达式计算了。

本文来自云栖社区合作伙伴“donet跨平台”,了解相关信息可以关注“opendotnet”微信公众号

继续阅读