C#脚本引擎CS-Script
最近想要在程序中嵌入一个C#脚本引擎,在.NET Framework时代用过一个叫做CS-Script的东西,感觉还是不错,发现现在也支持.NET Core了,试着嵌入一下。
比较
要说能够运行C#脚本的解决方案,有Roslyn和Mono,与他们相比,CS-Script能够提供的封装更为高级,它底层是通过Roslyn之类的引擎运行的,在此基础上,提供了一些额外功能:
- 执行完整的C#文件
- 通过外部进程执行C#文件
- 在运行过程中链接多个c#文件,并集成运行
- 提供简便的方法进行链接
- 脚本调试功能
当然也可以自己基于Roslyn去实现这些功能,不过CS-Script提供了更加简单的封装,适用于懒人。
使用
程序基于.NET 5的开发,尝试引用CS-Script包,发现不太好用,一直提示System.Reflection.TargetInvocationException:“Exception has been thrown by the target of an invocation.”。支持.NET Core的实际上是CS-Script.Core这个包,安装即可。
Install-Package CS-Script.Core
CS-Script实际上底层支持Mono/Roslyn/CodeDom三种脚本引擎,由于.NET CORE的特殊性,CS-Script.Core做了删减,只能支持Roslyn一种引擎了,支持的C#语言版本由Roslyn版本决定。
旁的不说,直接上代码:
using CSScriptLib;
using System;
using System.Reflection;
namespace ConsoleApp3
{
public class Program
{
static void Main(string[] args)
{
//var eval = CSScript.Evaluator.ReferenceAssemblyByNamespace("System.Text");
//var p = eval.ReferenceAssemblyByNamespace("ConsoleApp3");
Assembly compilemethod = CSScript.RoslynEvaluator.CompileMethod(
@"using System;
public static void CompileMethod(string greeting)
{
Console.WriteLine(""CompileMethod:"" + greeting);
}");
var p = compilemethod.GetType("css_root+DynamicClass");
var me = p.GetMethod("CompileMethod");
me.Invoke(null, new object[] { "1" });
//eval = CSScript.Evaluator.ReferenceAssembly(sqr);
dynamic loadmethod = CSScript.Evaluator.LoadMethod(@"using System;
public void LoadMethod(string greeting)
{
Console.WriteLine(""LoadMethod:"" +greeting);
}");
loadmethod.LoadMethod("Hello World!");
dynamic loadcode = CSScript.Evaluator
.LoadCode(@"using System;
using ConsoleApp31;
using System.Text;
public class ScriptCC
{
public void LoadCode(string greeting)
{
Console.WriteLine(""LoadCode:"" + greeting);
}
}");
loadcode.LoadCode("111");
var eval = CSScript.Evaluator.ReferenceDomainAssemblies(DomainAssemblies.AllStaticNonGAC);
var ass = eval
.CompileCode(@"using System;
public static class ScriptCCStatic
{
public static void LoadCodeStatic(string greeting)
{
Console.WriteLine(""LoadCodeStatic:"" + greeting);
}
}");
var tp = eval.CreateDelegate(@"int Sqr(int a)
{
return a * a;
}");
Console.WriteLine(tp(3));
eval = eval.ReferenceDomainAssemblies(DomainAssemblies.AllStaticNonGAC);
Assembly compilecode = eval
.CompileCode(@"using System;
using ConsoleApp31;//含有这个namespace的文件包含在本项目中。
using System.Text;
using ConsoleApp3;
public class ScriptLC
{
public void CompileCode(string greeting)
{
Console.WriteLine(""CompileCode:"" + greeting + Encoding.ASCII.IsBrowserDisplay);
Program.Write();
Test.Send();
}
}");
var ps = compilecode.GetType("css_root+ScriptLC");
var obj = compilecode.CreateInstance("css_root+ScriptLC");
var mes = ps.GetMethod("CompileCode");
mes.Invoke(obj, new object[] { "1" });
Console.WriteLine();
//查看evaluator的引用程序集
var ww = eval.GetReferencedAssemblies();
foreach (var n in ww)
{
if (n.GetName().Name.Contains("System")) continue;
if (n.GetName().Name.Contains("Microsoft")) continue;
if (n.GetName().Name.Contains("CS")) continue;
Console.WriteLine("AseemblyName: " + n.GetName());
foreach (var wn in n.GetTypes())
{
Console.WriteLine("Types: " + wn.Name);
}
}
Console.WriteLine();
//查看当前AppDomain加载的程序集
foreach (var n in AppDomain.CurrentDomain.GetAssemblies())
{
if (n.GetName().Name.Contains("System")) continue;
if (n.GetName().Name.Contains("Microsoft")) continue;
if (n.GetName().Name.Contains("CS")) continue;
Console.WriteLine("AseemblyName: " + n.GetName());
foreach (var wn in n.GetTypes())
{
Console.WriteLine("Types: " + wn.Name);
}
}
Console.ReadKey();
}
public static void Write()
{
Console.WriteLine("REFERENCE OK");
}
}
}
总结
使用CS-Script.Core的时候,所有加载/编译的方法与类型都动态加入了CurrentAppDomain,可以在主程序中进行调用(注意using和using static)。通过Evaluator.ReferenceAssembly等函数添加引用,不支持引用其他动态编译的代码段。
可以一次性将当前AppDomain的程序集引用加入Evaluator,但是一样,只能调用在文件中定义的程序集,无法加载其他动态程序集,调用Evaluator.ReferenceDomainAssemblies(DomainAssemblies.All)将提示错误。
这个限制是Roslyn导致的,暂时无法解决。如果需要实现多个代码段的互相调用,可以直接将代码段进行拼接,或者将公用的代码段存成文件,从文件中进行调用。
CompileMethod
编译方法,并返回动态生成的程序集,方法被默认加载到DynamicClass类中,该Type完全限定名称为css_root+DynamicClass,定义的静态方法需要使用以下方式调用。
var p = compilemethod.GetType("css_root+DynamicClass");
var me = p.GetMethod("CompileMethod");
me.Invoke(null, new object[] { "1" });
LoadMethod
加载方法,并返回默认类(DynamicClass)的一个对象,通过定义返回对象为dynamic类型,可以直接调用实例方法。
loadmethod.LoadMethod("Hello World!");
LoadCode
加载类,并返回代码段中的第一个类的实例,通过定义返回对象为dynamic类型,可以直接调用实例方法。
loadcode.LoadCode("111");
CompileCode
编译类,并返回动态生成的程序集,定义的实例方法可以使用以下方式调用。
var ps = compilecode.GetType("css_root+ScriptLC");
var obj = compilecode.CreateInstance("css_root+ScriptLC");
var mes = ps.GetMethod("CompileCode");
mes.Invoke(obj, new object[] { "1" });
Console.WriteLine();
CreateDelegate
生成一个委托,同样定义在DynamicClass中,可以直接调用。
var tp = eval.CreateDelegate(@"int Sqr(int a)
{
return a * a;
}");
Console.WriteLine(tp(3));
参考资料
附上直接通过Roslyn使用脚本的方法:Roslyn Scripting-API-Samples.md
C#脚本引擎CS-Script的更多相关文章
- [19/04/19-星期五] Java的动态性_脚本(Script,脚本)引擎执行JavaScript代码
一.概念 Java脚本引擎是jdk 6.0之后的新功能. 使得Java应用程序可以通过一套固定的接口与各种脚本引擎交互,从而达到在Java平台上调用各种脚本语言的目的. Java脚本API是连接Jav ...
- C#脚本引擎 CS-Script 之(二)——性能评测
以下以一个简单的HelloWord程序为例,来分析csscript脚本引擎的性能. class HelloWorld { public void SayHello() { Console.WriteL ...
- Java 8 的 Nashorn 脚本引擎教程
本文为了解所有关于 Nashorn JavaScript 引擎易于理解的代码例子. Nashorn JavaScript 引擎是Java SE 8的一部分,它与其它像Google V8 (它是Goog ...
- 【开源】.Net 动态脚本引擎NScript
开源地址: https://git.oschina.net/chejiangyi/NScript 开源QQ群: .net 开源基础服务 238543768 .Net 动态脚本引擎 NScript ...
- 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...
- Nmap源码分析(脚本引擎)
Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...
- 利用Roslyn构建一个简单的C#交互脚本引擎
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 微软的下一代编译器技术Roslyn是一个里程碑的技术,可以给.NET平台带来无限想象空间.比 ...
- C#脚本引擎 CS-Script 之(三)——如何部署
本文不但介绍了CS-Script如何部署,还介绍了CS-Script的部署后面的原理,并用一个框图详细介绍了部署中的各种细节. 一.获取资源 1.从官网上下载编译好的csscript资源:cs-scr ...
- C#脚本引擎 CS-Script 之(一)——初识
最近在做新产品,这个产品需要满足不同项目对于系统的定制性数据处理需求,比如有的要统计一段时间内某开关打开关闭了多少次,有的要统计一段时间内空调的使用率,有的希望根据温度来控制空调的开还是关,有的则是希 ...
- 无法找到脚本*.VBS的脚本引擎解决办法
当你在运行一些基于VBS脚本语言的文件时,系统可能报错.这时候可能是你的VBS脚本服务在注册表中出错了,原因可能是卸载或安装一些代码不规范的程序引起的.这里给出无法找到脚本引擎"vbscri ...
随机推荐
- Alpha冲刺——代码规范,冲刺计划
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE2/ 这个作业要求在哪里 https://edu.cnblogs.com/campus/f ...
- 关闭Win10窗口拖动到桌面边缘自动缩放功能
- kafka 消费组功能验证以及消费者数据重复数据丢失问题说明 3
原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 背景 上一篇文章记录了kafka的副本机制和容错功能的说明,本篇则主要在上一篇文章的基础上 ...
- 转:Python考核试题及答案
Python测试(总分:120) 选择题(每题2分,共20分) 1.下列哪个语句在Python中是非法的? (B) A.x = y = z = 1 B.x = (y = z + 1) C.x, y = ...
- PyQt(Python+Qt)学习随笔:Qt Designer中toolBar的toolButtonStyle属性
tooButtonStyle属性保存主工具栏按钮的样式设置,用来表示工具栏按钮的文字和图标怎么显示. 该属性的可设置值类型为枚举类型Qt.ToolButtonStyle,它包含如下值: 该属性的缺省值 ...
- ollvm在VS2017下编译
0x1,首先介绍一下编译环境配置 1.UE4.25 2.vs2017(15.9),注:2019编译总是出现错误 3.cmake3.18.5,cmake的作用是为ollvm源码编译成适合于在vs2017 ...
- CTF写脚本
今天总结一下CTF如何写脚本快速得分....(比较菜,能力有限,大佬勿喷) 所谓的写脚本得分,就是利用了 python爬虫的思想,如果之前没有听说过的话,可以去爬虫的相关语法.如果是看网上的视频的话, ...
- 介质访问控制子层-Medium Access Control Sublayer:多路访问协议、以太网、无线局域网
第四章 介质访问控制子层-Medium Access Control Sub-layer 4.1介质访问控制子层概述 MAC子层不属于之前提到的OSI或TCP/IP架构的任何一层,这也是为什么这一层被 ...
- HDU3306 Another kind of Fibonacci
本篇题解用于作者本人对于矩阵乘法的印象加深,也欢迎大家的阅读. 题目大意 众所周知,斐波那契数列为 \(f(0)=1\) , \(f(1)=1\) ,\(f(n)=f(n-1)+f(n-2)~(n&g ...
- 笔记-Recursive Queries
Recursive Queries \[m_{l,r}=\textrm{id}(\max_{i=l}^r a_i)\\ f(l,r)= \begin{cases} (r-l+1)+f(l,m_{l,r ...