通过Roslyn构建自己的C#脚本

通过Roslyn构建自己的C#脚本

在下一代的C#中,一个重要的特性就是"Compiler as a Service",简单的讲,就是就是将编译器开放为一种可在代码中调用的服务。最近使用了一下微软放出的Project Roslyn CTP版,感觉还是非常强大的。

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

  1. 在微软的网站下载Roslyn CTP版并安装
  2. 在工程中添加Roslyn.Compilers.dll和Roslyn.Compilers.CSharp.dll的引用
  3. 在代码中增加如下命名空间的引用。
    using Roslyn.Scripting;
    using Roslyn.Scripting.CSharp;

经典的HelloWorld

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

static void Main(string[] args)
    {
        var scriptEngine = new ScriptEngine();
        scriptEngine.Execute("System.Console.WriteLine(\"hello world\")");
    }

从上述代码中可以看出,执行一个脚本还是比较简单的,只要创建一个ScriptEngine对象,然后就可以通过ScriptEngine.Execute()函数执行自己的脚本了。

如果我们要获取脚本的返回值,也是很容易的。

var result = scriptEngine.Execute<int>("3+2*5");
    Console.WriteLine(result);

在会话中执行脚本

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

var scriptEngine = new ScriptEngine();
    scriptEngine.Execute("var i = 3;");
    var result = scriptEngine.Execute("i * 2");

得到的并不是我们想要的结果6,而是一个异常:(1,1): error CS0103: The name ‘i‘ does not exist in the current context。

究其原因,是因为ScriptEngine.Execute()函数每次都是在一个单独的上下文中执行的,并不会和前面的语句产生关联。如果我们要在ScriptEngine.Execute()函数中添加Session参数,以标明其是在同一个会话中的。正确方式如下:

var scriptEngine = new ScriptEngine();
    var session = Session.Create();
    scriptEngine.Execute("var i = 3;", session);
    var result = scriptEngine.Execute("i * 2", session);

在脚本和程序中共享数据

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

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

还是举一个简单的例子吧:

namespace Host
    {
        public class HostObject
        {
            public string State = "Hello";
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            var hostReference = new Roslyn.Compilers.AssemblyFileReference(typeof(Host.HostObject).Assembly.Location);
            var engine = new ScriptEngine(references: new[] { hostReference }, importedNamespaces: new[] { "System" });
            var host = new Host.HostObject();
            var session = Session.Create(host);

var result = engine.Execute<string>("State + State", session);
            Console.WriteLine(result);

host.State = "Go Go hello ";
            result = engine.Execute<string>("State + State", session);
            Console.WriteLine(result);
        }
    }

这里首先创建了一个HostObject类型的宿主对象host,再由它创建会话。这样就将host对象的成员变量State嵌入了脚本中,在脚本和程序中都能共享State变量了。

时间: 2024-10-10 21:23:00

通过Roslyn构建自己的C#脚本的相关文章

通过Roslyn构建自己的C#脚本(更新版)

之前写过文章介绍过如何通过Roslyn构建自己的C#脚本,但那篇文章是参考自Roslyn CTP版的,记得本来想等到Roslyn正式版出来重新更新一下文档的,不过记得后来Roslyn是跳票了的,Scripting API在正式版本中都一度被移除了,这个更新就没有做下去了. 最近看到有人在原文中询问如何使用C# Script API,便查询了一下相关资料,这个功能是在的VS2015 update 1中才正式放出的,其时已经到16年了,使用方法与之前已经大有不同了,便重新写一篇介绍下如何使用C# S

通过Roslyn构建自己的C#脚本(更新版)(转)

? http://www.cnblogs.com/TianFang/p/6939723.html ? 之前写过文章介绍过如何通过Roslyn构建自己的C#脚本,但那篇文章是参考自Roslyn CTP版的,记得本来想等到Roslyn正式版出来重新更新一下文档的,不过记得后来Roslyn是跳票了的,Scripting API在正式版本中都一度被移除了,这个更新就没有做下去了. 最近看到有人在原文中询问如何使用C# Script API,便查询了一下相关资料,这个功能是在的VS2015 update

ant构建web项目build脚本

build.xml <?xml version="1.0" encoding="UTF-8" standalone="no"?> <project name="edu_2.0" basedir="." default="war"> <!--引入配置信息--> <property file="build.properties"

Jmeter - 构建1个可供Linux使用的Jmeter测试脚本 - 共3个步骤

在Linux使用Jmeter做性能测试需要4个前提条件,这4个前提条件已经在之前的文档里提到了,重复一下加深印象: (1) 在本地已安装xshell 参考<SecureCRT-转换密钥-Xshell-配置服务-使用xshell登录远程linux服务器> (2) 在Linux有Java运行环境 参考<Jmeter-安装JDK- 配置Jmeter运行的环境 - 是使用Jmeter的前提> (3) 在Linux已安装Jmeter 参考<Jmeter-安装Jmeter - 在Linu

nixyx —— 一个小巧的项目工程/编译文件生成器(构建系统?)

恩..nixyx确实算不上是一个构建系统. 所谓构建系统,比如GNU的Autotools,那是一套很完整的构建体系,包括了程序的配置,编译和安装三大部分. 类似的软件还有:google的gyp.腾讯的Blade等.它们最大的好处在于,可以不考虑平台之间的差别,使用统一的配置文件和命令,做到跨平台部署. 它们往往还支持很多很高端的功能,比如集成自动测试,代码检查(Blade).. 可是我暂时不需要这些复杂的功能.我正在编写的nixy库是一个跨平台/编译器的C++库,它非常小,没必要使用大型的(或者

vim脚本(一)

优秀的文本编辑器 有这样一则老笑话:如果 Emacs 拥有一款优良的文本编辑器,那么它将是一个优秀的操作系统,相反,如果 vi 拥有一个不错的操作系统,那么它将是一款非常出色的文本编辑器.这个笑话反映了 Emacs 有一个一直比 vi 好的策略优势:一种嵌入式扩展编程语言.实际上,Emacs 用户一直乐于忍受引入了 RSI 的控制问题,并且愿意在 Lisp 中编写他们的扩展,这个事实展示了内置扩展语言的强大优势. 现在,vi 程序员不再需要向 Emacs 的插入式脚本语言投去嫉妒的眼光.我们最喜

Gradle脚本基础全攻略

[工匠若水 http://blog.csdn.net/yanbober 转载请注明出处.点我开始Android技术交流] 1 背景 在开始Gradle之前请务必保证自己已经初步了解了Groovy脚本,特别是闭包规则,如果还不了解Groovy则可以先看<Groovy脚本基础全攻略>这一篇博客速成一下Groovy基础,然后再看此文即可.关于Gradle速成干货基础详情也请参考Geadle官方网站,不好意思我太Low了. Gradle核心是基于Groovy的领域特定语言(DSL,具体概念参见<

构建Nginx服务器之三 反向代理Discuz论坛

实验目的: 利用nginx均衡两台lamp下Discuz,其中任意一台lamp的web 宕机,不影响discuz的使用! 实验拓扑: 实验环境: 服务器                           主机名                 IP地址 Nginx服务器                      nginx                  192.168.1.2 Discuz论坛(主mysql)              master                 192.

gulp静态资源构建、压缩、版本号添加

公司移动端商城使用前后分离方案,前台nginx静态文件,js使用requirejs模式,使用gulp压缩添加版本号时发现问题, 问题1.在公共的js配置中,引用的路径是写死的,缓存会一直存在. 解决方案是添加 urlArgs 构建时用shell脚本替换 'ttversion'为一个随机数值,我用的是当前时间. 问题2.其他模块引用的是common,那common.js不变的话,缓存会一直存在. 解决方案:还是用shell脚本,首先更改common.js为common_随机数.js,再更改所有引用