C#脚本引擎CS-Script
要说能够运行C#脚本的解决方案,有Roslyn和Mono,与他们相比,CS-Script能够提供的封装更为高级,它底层是通过Roslyn之类的引擎运行的,在此基础上,提供了一些额外功能:
- 执行完整的C#文件
- 通过外部进程执行C#文件
- 在运行过程中链接多个c#文件,并集成运行
- 提供简便的方法进行链接
- 脚本调试功能
注:由于技术发展,很多功能可能已经被Roslyn支持了。同时基于web有Try.NET和SharpLab等优秀方案。
当然也可以自己基于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
这个包,安装即可。
dotnet add package CS-Script.Core
CS-Script
实际上底层支持Mono/Roslyn/CodeDom三种脚本引擎,由于.NET CORE的特殊性,CS-Script.Core做了删减,只能支持Roslyn一种引擎了,支持的C#语言版本由Roslyn版本决定。
旁的不说,直接上代码:
using System;
using System.Reflection;
using CSScriptLib;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");}}
}namespace ConsoleApp31
{public class Test{public static void Send(){Console.WriteLine("ConsoleApp31 Test Send");}}
}
总结#
使用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
作者: 波多尔斯基
出处:https://www.cnblogs.com/podolski/p/14192599.html
版权:本文采用「署名 4.0 国际」知识共享许可协议进行许可。
欢迎转载,转载请保留原文链接~喜欢的观众老爷们可以点下推荐或者右下角关注不迷路~
C#脚本引擎CS-Script相关推荐
- java fel_Java表达式引擎fel/groovy/expression4j/java脚本引擎的性能对比【原创】
又是性能对比,最近跟性能较上劲了. 产品中需要用到数学表达式,表达式不复杂,但是对性能要求比较高.选用了一些常用的表达式引擎计算方案,包含:java脚本引擎(javax/script).groovy脚 ...
- 从比特币脚本引擎到以太坊虚拟机
这个系列是目标受众是区块链开发者和有其他开发经验的CS专业学生 面对媒体对区块链相关技术的解读和吹捧,许多人一时不知所措.投资人.大公司都在FOMO(fear of missing out)的心理驱动 ...
- 写给开发者——从比特币脚本引擎到以太坊虚拟机
这个系列的目标受众是区块链开发者和CS专业同学 面对媒体对区块链相关技术的解读和吹捧,许多人一时不知所措.投资人.大公司都在FOMO(fear of missing out)的心理驱动下,争相宣布al ...
- flash脚本引擎LegendForFlashProgramming0.1版发布
一,LegendForFlashProgramming脚本引擎是什么? 它是一个用ActionScript3.0开发的游戏脚本引擎,游戏里的所有元素都可以由脚本语言来控制,它可以轻松制作一款SLG游戏 ...
- 在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统
在<在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎>开始处,我提到某公司被指责使用"云命令"暗杀一些软件.本文将讲述如何去模拟一个 ...
- 复杂多变场景下的Groovy脚本引擎实战
作者:vivo互联网服务器团队-Gao Xiang 一.前言 因为之前在项目中使用了Groovy对业务能力进行一些扩展,效果比较好,所以简单记录分享一下,这里你可以了解: 为什么选用Groovy作为脚 ...
- java7 javascript引擎_Java7中脚本引擎的一般用法,共三种方法获得JavaScript引擎:名称、文件扩展名、MIME类型 | 学步园...
package com.sino.java7; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; i ...
- .NET简谈脚本引擎系列(一:认识脚本引擎)
提到脚本,大家都耳熟能详但是默默无私奉献的脚本引擎都被大家所忽略,本人也是最近才开始接触脚本引擎的技术的,是我的恩师指点我去学习它, 真是不用不不知道,一用吓一跳:如果我们能熟练的使用脚本引擎,那么将 ...
- jsr223 java_JSR223 Java使用脚本引擎动态修改业务逻辑
本文来自图灵社区 @fairjm 转截请注明出处 偶尔会有一些业务需求是需要在动态改变线上代码的行为.一般的做法是使用个配置文件,存在数据库或者redis等存储中,程序动态获取之后解析并根据配置进行相 ...
- Nmap源码分析(脚本引擎)
Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...
最新文章
- JS设计模式学习实例之单例模式
- MySQL第一篇 (linux ubuntu平台 学习《MySQL技术内幕》总结)
- Selenium Webdriver——操作隐藏的元素(三)switchTo().frame()
- 使用第三方《UITableView+FDTemplateLayoutCell》自动计算UITableViewCell高度(Masonry约束)...
- 第十节: 利用SQLServer实现Quartz的持久化和双机热备的集群模式 :
- python date2num_坚持mdates.date2num
- Cent OS6.6 的vsftps 的root上传配置
- 假短信截图在线生成器_10个超好玩的自动生成器
- Ubuntu22 超nice的QQ(Icalingua++)安装步骤,拒绝走弯路!!
- x509 java_Java X509证书解析和验证
- 什么叫SYN包,什么是SYN包***?
- 虚拟机安装ubuntu server及工作环境搭建
- IPC Send timeout detected模拟和总结
- 什么是局域网监控?是如何监控的...
- 苏嵌//张福辉//2018.7.27
- 【MAX7800与ESP8266mcu通讯关键字控制】
- 全球与中国阻燃海绵市场深度研究分析报告
- 2729:Blah数集
- 微软拼音输入法15周年
- html中插入wmv格式视频文件的代码
热门文章
- 细则从哈利·波特与来自您好麻雀船长
- C语言经典题目:求阶乘n!=n*(n-1)*...*1,阶乘和s=1!+(2)!+(3)!+...+n!
- java个人博客源码ssm_基于SSM的个人博客系统源代码
- 树形选择排序(第十章 P279)
- java有除数为零_java语言中除数为零问题
- 【深度学习】CNN+Transformer汇总
- C语言>>输入两个字符串,比较这两个字符串是否相同并输出比较结果。要求不用任何字符串处理函数。
- 【格式化文档】ISO27001控制措施+ISO27002实施指南 【上】
- Rect.OverLaps() 改进
- 调用百度AI开放平台实现图片文字识别