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 ...
随机推荐
- mysql主从同步下---主从配置
1.安装mysql主从服务器 1.1 初始化docker中mysql挂载目录 # 新建2个目录, 存放master和slave的配置和数据, cd ~ # ~ 代表家目录 /home/你的用户名/ ...
- .net core3.1开始页面实时编译
安装NuGet包 Install-Package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation startup.cs 中的ConfigureSe ...
- 新手上路之JDK11的下载、安装与PATH环境变量的配置
目录 JDK11的下载 找到目标JDK JDK的下载 JDK11的安装 PATH环境变量的配置 为什么要配置环境变量? 配置前再检查一遍 配置变量 检查环境变量配置成功与否 细究起来,JDK11与JD ...
- 你的Idea还可用吗?不妨试试这个神器!
@ 目录 一.STS安装 1.STS下载 2.STS安装 二.STS使用 1.STS配置JDK 2.STS配置Maven 3.使用STS创建SpringBoot项目 三.优化STS 1.主题美化 2. ...
- JQuery 和 Bootstrap
https://jquery.com/ 1. JQuery 的基础语法 $(select).action() 2. 查找标签 基本选择器 class选择器: $(".className&q ...
- 20200523_mysql中文乱码
查看字符集: 方法一:show variables like '%character%'; 方法二:show variables like 'collation%';设置字符集: /*建立连接使用的编 ...
- kali-网络桥接
kali 之网络桥接 前言:之前一直选择的是nat模式,不知道我的什么神操作,kali的网络突然就挂掉了,然后就是重启,配置,一直轮训下去,还是ping不通主机,搞得心态差点爆炸,于是乎就放弃了nat ...
- 如何自动化你的Excel导入导出(Java)?
GitHub | 中文 | English | 博客 为什么使用AutoExcel? Excel导入导出在软件开发中非常常见,只要你接触过开发,就一定会遇到.相信很多人会跟我一样选择用Apache P ...
- Python中的enumerate函数的作用
enumerate函数是将一个可迭代对象中元素,按元素顺序每个增加一个索引值,将其组成一个索引序列,利用它可以同时获得索引和值,这样做的目的是为了将一个可迭代对象中元素组成一个"索引,值&q ...
- windows下使用pyinstaller将多个目录的Python文件打包成exe可执行文件
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 需要将一个工程涉及两个目录的模块文件打包成exe,打包环境如 ...