C# 腳本引擎CS-Script的使用
最近想要在程序中嵌入一個(gè)C#腳本引擎,在.NET Framework時(shí)代用過(guò)一個(gè)叫做CS-Script的東西,感覺(jué)還是不錯(cuò),發(fā)現(xiàn)現(xiàn)在也支持.NET Core了,試著嵌入一下。
比較
要說(shuō)能夠運(yùn)行C#腳本的解決方案,有Roslyn和Mono,與他們相比,CS-Script能夠提供的封裝更為高級(jí),它底層是通過(guò)Roslyn之類(lèi)的引擎運(yùn)行的,在此基礎(chǔ)上,提供了一些額外功能:
- 執(zhí)行完整的C#文件
- 通過(guò)外部進(jìn)程執(zhí)行C#文件
- 在運(yùn)行過(guò)程中鏈接多個(gè)c#文件,并集成運(yùn)行
- 提供簡(jiǎn)便的方法進(jìn)行鏈接
- 腳本調(diào)試功能
注:由于技術(shù)發(fā)展,很多功能可能已經(jīng)被Roslyn支持了。同時(shí)基于web有Try.NET和SharpLab等優(yōu)秀方案。
當(dāng)然也可以自己基于Roslyn去實(shí)現(xiàn)這些功能,不過(guò)CS-Script提供了更加簡(jiǎn)單的封裝,適用于懶人。
使用
程序基于.NET 5的開(kāi)發(fā),嘗試引用CS-Script包,發(fā)現(xiàn)不太好用,一直提示System.Reflection.TargetInvocationException:“Exception has been thrown by the target of an invocation.”。支持.NET Core的實(shí)際上是CS-Script.Core這個(gè)包,安裝即可。
Install-Package CS-Script.Core
CS-Script實(shí)際上底層支持Mono/Roslyn/CodeDom三種腳本引擎,由于.NET CORE的特殊性,CS-Script.Core做了刪減,只能支持Roslyn一種引擎了,支持的C#語(yǔ)言版本由Roslyn版本決定。
旁的不說(shuō),直接上代碼:
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;//含有這個(gè)namespace的文件包含在本項(xiàng)目中。 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(); //查看當(dāng)前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"); } } }
總結(jié)
使用CS-Script.Core的時(shí)候,所有加載/編譯的方法與類(lèi)型都動(dòng)態(tài)加入了CurrentAppDomain,可以在主程序中進(jìn)行調(diào)用(注意using和using static)。通過(guò)Evaluator.ReferenceAssembly等函數(shù)添加引用,不支持引用其他動(dòng)態(tài)編譯的代碼段。
可以一次性將當(dāng)前AppDomain的程序集引用加入Evaluator,但是一樣,只能調(diào)用在文件中定義的程序集,無(wú)法加載其他動(dòng)態(tài)程序集,調(diào)用Evaluator.ReferenceDomainAssemblies(DomainAssemblies.All)將提示錯(cuò)誤。
這個(gè)限制是Roslyn導(dǎo)致的,暫時(shí)無(wú)法解決。如果需要實(shí)現(xiàn)多個(gè)代碼段的互相調(diào)用,可以直接將代碼段進(jìn)行拼接,或者將公用的代碼段存成文件,從文件中進(jìn)行調(diào)用。
CompileMethod
編譯方法,并返回動(dòng)態(tài)生成的程序集,方法被默認(rèn)加載到DynamicClass類(lèi)中,該Type完全限定名稱(chēng)為css_root+DynamicClass,定義的靜態(tài)方法需要使用以下方式調(diào)用。
var p = compilemethod.GetType("css_root+DynamicClass"); var me = p.GetMethod("CompileMethod"); me.Invoke(null, new object[] { "1" });
LoadMethod
加載方法,并返回默認(rèn)類(lèi)(DynamicClass)的一個(gè)對(duì)象,通過(guò)定義返回對(duì)象為dynamic類(lèi)型,可以直接調(diào)用實(shí)例方法。
loadmethod.LoadMethod("Hello World!");
LoadCode
加載類(lèi),并返回代碼段中的第一個(gè)類(lèi)的實(shí)例,通過(guò)定義返回對(duì)象為dynamic類(lèi)型,可以直接調(diào)用實(shí)例方法。
loadcode.LoadCode("111");
CompileCode
編譯類(lèi),并返回動(dòng)態(tài)生成的程序集,定義的實(shí)例方法可以使用以下方式調(diào)用。
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
生成一個(gè)委托,同樣定義在DynamicClass中,可以直接調(diào)用。
var tp = eval.CreateDelegate(@"int Sqr(int a) { return a * a; }"); Console.WriteLine(tp(3));
參考資料
附上直接通過(guò)Roslyn使用腳本的方法:Roslyn Scripting-API-Samples.md
以上就是C#腳本引擎CS-Script的使用的詳細(xì)內(nèi)容,更多關(guān)于C#腳本引擎CS-Script的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解C# Socket簡(jiǎn)單例子(服務(wù)器與客戶(hù)端通信)
這篇文章主要介紹了詳解C# Socket簡(jiǎn)單例子(服務(wù)器與客戶(hù)端通信) ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-12-12C#使用SQL DataAdapter數(shù)據(jù)適配代碼實(shí)例
今天小編就為大家分享一篇關(guān)于C#使用SQL DataAdapter數(shù)據(jù)適配代碼實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10C#?WPF中RadioButton控件的用法及應(yīng)用場(chǎng)景
在WPF應(yīng)用程序中,RadioButton控件是一種常用的用戶(hù)界面元素,本文主要介紹了C#?WPF中RadioButton控件的用法及應(yīng)用場(chǎng)景,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03使用C#實(shí)現(xiàn)Windows組和用戶(hù)管理的示例代碼
這篇文章主要介紹了使用C#實(shí)現(xiàn)Windows組和用戶(hù)管理的示例代碼,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-01-01