2020結束前擼一個android簡單banner(輪播)
返回主頁 波多爾斯基
部落格園 首頁標籤歸檔 訂閱 管理
C#指令碼引擎CS-Script
最近想要在程式中嵌入一個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這個包,安裝即可。
Copy
Install-Package CS-Script.Core
CS-Script實際上底層支援Mono/Roslyn/CodeDom三種指令碼引擎,由於.NET CORE的特殊性,CS-Script.Core做了刪減,只能支援Roslyn一種引擎了,支援的C#語言版本由Roslyn版本決定。
旁的不說,直接上程式碼:
Copy
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(
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,定義的靜態方法需要使用以下方式呼叫。
Copy
var p = compilemethod.GetType(“css_root+DynamicClass”);
var me = p.GetMethod(“CompileMethod”);
me.Invoke(null, new object[] { “1” });
LoadMethod#
載入方法,並返回預設類(DynamicClass)的一個物件,通過定義返回物件為dynamic型別,可以直接呼叫例項方法。
Copy
loadmethod.LoadMethod(“Hello World!”);
LoadCode#
載入類,並返回程式碼段中的第一個類的例項,通過定義返回物件為dynamic型別,可以直接呼叫例項方法。
Copy
loadcode.LoadCode(“111”);
CompileCode#
編譯類,並返回動態生成的程式集,定義的例項方法可以使用以下方式呼叫。
Copy
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中,可以直接呼叫。
Copy
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 國際」知識共享許可協議進行許可。
歡迎轉載,轉載請保留原文連結喜歡的觀眾老爺們可以點下推薦或者右下角關注不迷路
分類: .NET Core
標籤: 指令碼, c#, .NET
3 0
« 上一篇: Protobuf簡單型別直接反序列化方法
posted @ 2020-12-28 11:12 波多爾斯基 閱讀(248) 評論(5) 編輯 收藏
評論列表
#1樓 2020-12-28 11:27 民工也Coding
好厲害!
支援(0) 反對(0)
#2樓 2020-12-28 12:27 yi念之間
good,這個是基於roslyn的嗎?
支援(0) 反對(0)
#3樓 2020-12-28 12:42 老三的古代
目前的指令碼話都卡在依賴引用上,純粹指令碼的話還是比較基礎。
支援(0) 反對(0)
#4樓 [樓主] 2020-12-28 12:48 波多爾斯基
@yi念之間
Core版本是基於Roslyn的,標準版本可以基於Roslyn、mono或者codedom。
支援(0) 反對(0)
#5樓 [樓主] 2020-12-28 12:51 波多爾斯基
@老三的古代
依賴引用文中有描述,只要不是引用動態編譯的程式集,應該都有辦法。如果需要引用動態編譯的程式集,Roslyn就暫時不行了,可以試試別的。
支援(0) 反對(0)
登入後才能發表評論,立即 登入 或 註冊, 訪問 網站首頁
寫給園友們的一封求助信
Copyright © 2020 波多爾斯基
Powered by .NET 5.0 on Kubernetes & Theme Silence v2.0.2
CONTENTS
✕
- 比較
- 使用
- 總結
3.1. CompileMethod
3.2. LoadMethod
3.3. LoadCode
3.4. CompileCode
3.5. CreateDelegate - 參考資料