C# 脚本引擎CS-Script的使用

Kamilia ·
更新时间:2024-09-20
· 748 次阅读

最近想要在程序中嵌入一个C#脚本引擎,在.NET Framework时代用过一个叫做CS-Script的东西,感觉还是不错,发现现在也支持.NET Core了,试着嵌入一下。

比较

要说能够运行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这个包,安装即可。

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的使用的详细内容,更多关于C#脚本引擎CS-Script的资料请关注软件开发网其它相关文章!

您可能感兴趣的文章:利用FlubuCore用C#来写DevOps脚本的方法详解C#调用python脚本的方法步骤(2种)在VS2017中用C#调用python脚本的实现微信跳一跳自动脚本C#代码实现使用C# 的webBrowser写模拟器时的javascript脚本调用问题C#调用Python脚本的简单示例总结ASP.NET C#中经常用到的13个JS脚本代码C#创建数据库及导入sql脚本的方法C#利用ScriptControl动态执行JS和VBS脚本在C#中调用VBScript、javascript等脚本的实现代码常用工具之 vb转化C# 数据连接串 正则表达式查询 源码世界 脚本字典



C# script 脚本

需要 登录 后方可回复, 如果你还没有账号请 注册新账号