zoukankan      html  css  js  c++  java
  • 使用 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、在代码中增加如下命名空间的引用。

    using Microsoft.CodeAnalysis.CSharp.Scripting;
    using Microsoft.CodeAnalysis.Scripting;

    经典的HelloWorld

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

    static void Main(string[] args)
        {
               var options =
                   ScriptOptions.Default
                  .AddReferences("System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");

               var bar = new Bar() { StaffId = 5686, UnitId = 2 , Age = 15};
               Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync("System.Console.WriteLine("hello world");", options);

        }

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

    var scriptState = CSharpScript.RunAsync<int>("3+2*5", ScriptOptions.Default);

    Console.WriteLine(scriptState );

    在会话中执行脚本

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

    Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync("var i = 3;");
    var result = Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync("i * 2");

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

    image

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

    var s0 = CSharpScript.Create("int x = 1;");
               var s1 = s0.ContinueWith("int y = 2;");           
               var s2 = s1.ContinueWith<int>("x + y");
               Console.WriteLine(s2.RunAsync().Result.ReturnValue);

    在脚本和程序中共享数据

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

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

    namespace RoslynCosonle
    {
        class Program
        {
            static void Main(string[] args)
            {
                var options =
                    ScriptOptions.Default
                   .AddReferences("System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");         

                var s0 = CSharpScript.Create("int x = 1;");
                var s1 = s0.ContinueWith("int y = 2;");           
                var s2 = s1.ContinueWith<int>("x + y");
                Console.WriteLine(s2.RunAsync().Result.ReturnValue);

              

               var bar = new Bar() { StaffId = 5686, UnitId = 2 , Age = 15};
                Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.RunAsync("System.Console.WriteLine( (StaffId==5686 && UnitId==2)||( UnitId == 3|| Age >10) );", options, bar);

     
            }
        }

        public class Bar
        {
            public string Foo => "Hello World!";
           
            public int StaffId { get; set; }

            public int UnitId { get; set; }

            public int Age { get; set; }
        }

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

  • 相关阅读:
    L18 如何快速查找文档获得帮助
    L4 如何在XCode中下进行工作
    L17 怎么向应用程序商店提交应用
    Unity 烘焙材质到单一贴图的脚本
    关于用Max导出Unity3D使用的FBX文件流程注解
    计算两点之间的角度的代码
    Unity3d iOS基本优化和高级优化
    91SDK接入及游戏发布、更新指南
    UNITY3D与iOS交互解决方案
    Unity3d与iOS交互开发——接入平台SDK必备技能
  • 原文地址:https://www.cnblogs.com/shanyou/p/6224582.html
Copyright © 2011-2022 走看看