在下一代的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变量了。

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

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

      http://www.cnblogs.com/TianFang/p/6939723.html   之前写过文章介绍过如何通过Roslyn构建自己的C#脚本,但那篇文章是参考自Roslyn CTP版 ...

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

    之前写过文章介绍过如何通过Roslyn构建自己的C#脚本,但那篇文章是参考自Roslyn CTP版的,记得本来想等到Roslyn正式版出来重新更新一下文档的,不过记得后来Roslyn是跳票了的,Scr ...

  3. Jenkins构建完成之后运行脚本可以杀掉TomCat但是起不来的解决方法

    Jenkins构建完成之后运行脚本可以杀掉TomCat但是起不来的解决方法 写了一个重启tomcat的脚本,让jenkins编译.打包.发布时调用.在本地写好重启tomcat的脚本后,本地执行脚本没有 ...

  4. 利用Roslyn构建一个简单的C#交互脚本引擎

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 微软的下一代编译器技术Roslyn是一个里程碑的技术,可以给.NET平台带来无限想象空间.比 ...

  5. Skia构建系统与编译脚本分析

    分析下Skia的构建系统,详细编译过程參看Windows下从源代码编译Skia.这里以ninja为例来分析.运行以下三条命令就能够完毕编译: SET "GYP_GENERATORS=ninj ...

  6. Roslyn(CSharpScript).Net脚本编译引擎使用过程内存增涨与稳定的方式

    目       录 1.      引用程序集... 1 2.      内存增涨的情况... 2 3.      内存稳定的情况... 4 1.   引用程序集 Roslyn 是微软公司开源的 .N ...

  7. 通过Roslyn动态生成程序集

    之前写过篇文章如何通过Roslyn构建自己的C#脚本,今天本来打算测试一下这部分API在新的版本中的变化,结果发现它的脚本引擎找不到了,翻了一下官方文档,貌似说暂时性的移除了.便看了一下它动态生成程序 ...

  8. Roslyn 静态分析

    本文告诉大家如何使用 Roslyn 分析代码 首先创建一个项目,项目使用.net Framework 4.6.2 ,控制台项目.然后需要安装一些需要的库 Nuget 安装 打开 Nuget 安装下面两 ...

  9. 2018-8-29-Roslyn-静态分析

    title author date CreateTime categories Roslyn 静态分析 lindexi 2018-08-29 09:10:19 +0800 2018-03-13 14: ...

随机推荐

  1. centos7 pxe minimal install

    # 01-78-2b-cb-69-10-f3 default menu.c32 prompt 0 timeout 50 label CentOS 7 MENU DEFAULT MENU LABEL C ...

  2. 【转】DDR3详解(以Micron MT41J128M8 1Gb DDR3 SDRAM为例)

    这两天正在学习FPGA如何控制DDR3的读写,找到一篇个人感觉比较有意义的文章,可以对DDR的内部结构有一个初步的了解.原文出处:http://blog.chinaunix.net/uid-28458 ...

  3. 如何避免遭受HTTS中间人攻击

    先前为大家说明了如何对App的HTTPS通讯进行中间人攻击,听起来很吓人吧-表示若是使用手机的网银或购物等App,便有可能暴露在风险之中. 会发生HTTPS遭受拦截的主要原因是客户端的App未对服务器 ...

  4. LLVM language 参考手册(译)(3)

    可见性模式(Visibility Styles) 所有全局变量和函数具有以下的可见性模式之一: “default” - Default style 在那些使用ELF object file格式的平台( ...

  5. phalcon框架学习之router

    router定义 在DI中注册router的方法: $di->set('router', function(){ $router = new Phalcon\Mvc\Router(); $rou ...

  6. Js 访问Aspnet后台页面变量

    一.普通WebForm页面 <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server ...

  7. 软件工程 speedsnail 第二次冲刺5

    20150522 完成任务:蜗牛帧数变化已经实现,行走的蜗牛具有了动态的视觉效果: 遇到问题: 问题1 帧数大小根据人眼来设置 解决1 除29余0到14的为第一帧 明日任务: 蜗牛碰撞身体翻转

  8. 03-图片浏览器(plist的简单应用)

    ViewController.h文件中: @interface ViewController : UIViewController - (IBAction)sliderValueChange:(UIS ...

  9. 一个用WPF做的简单计算器源代码

    一.界面设计XAML代码 <Window x:Class="fengjisuanqi.MainWindow" xmlns="http://schemas.micro ...

  10. js中forEach无法跳出循环?

    1. forEach() forEach() 方法从头至尾遍历数组,为每个元素调用指定的函数.如上所述,传递的函数作为forEach()的第一个参数.然后forEach()使用三个参数调用该 函数:数 ...