當前位置: 妍妍網 > 碼農

動態編程神器! 探秘.Net中的AI時代秘密武器——Natasha框架全解析

2024-01-26碼農

在開發領域,我們經常會遇到需要動態載入和執行程式碼的場景。對於 Python JavaScript、Lua 等手稿語言,動態性是它們的天性,而對於需要預先編譯的語言,如 C# ,動態執行似乎並不那麽直觀。但隨著 AI 的普及, 例如我們想在C#程式中動態執行AI生成的程式碼段,這就要求我們能在執行時編譯和執行C#程式碼 。接下來,讓我為你介紹一個強大的框架—— Natasha

Natasha:動態地構建你的.Net世界

Natasha 是一個基於 Roslyn 的C#動態程式集構建庫。它允許開發者在程式執行時動態地構建域、程式集、類、結構體、列舉、介面和方法等。這意味著開發者可以在不停止應用程式的情況下,為其增加新的程式集。

Natasha 框架具備域管理和外掛程式管理功能,支持域的隔離和解除安裝,實作了熱插拔。它提供了完善的錯誤提示,自動添加參照,並且擁有完整的數據結構構建樣版,從而讓開發者專註於程式集指令碼的編寫。更何況它還有著跨平台的優勢,並且對 netcoreapp2.0+ / netcoreapp3.0+ 都相容。

Natasha的使用場景

你可能會好奇,這樣一個動態編譯庫是如何彰顯其價值的?其實,動態編譯技術是支撐如今.NET生態不可或缺的重要部份。無論是在官方還是非官方的庫中,動態編譯的技術都扮演著「服務」的角色。其核心是 MSIL ,官方為我們提供了 Emit 技術來編寫IL程式碼。但 Emit 的編寫和維護並不友好,給開發者帶來了諸多挑戰。

Roslyn 的出現仿佛開啟了新世界的大門,它使得 Emit 變得透明,並允許我們直接用C#進行動態編譯。 Natasha 就是在這樣的基礎上發展起來的,經過精心設計與不斷叠代,它正成為動態編譯領域的佼佼者。


Natasha的簡單套用場景

借助Natasha,你可以實作眾多有趣而實用的功能,如建立AOP代理類或動態構建Controller來實作動態API,甚至在程式啟動時與CodeFirst相容的ORM一起使用,動態建立表結構,甚至透過動態執行AI建立的程式碼段,這是個非常有趣的事情!

不可否認,這些功能的實作需要一定的編程基礎。例如,下面的程式碼展示了如何使用Natasha快速開始一個域,並利用其外掛程式管理功能。

// 開始建立域var domain = new NatashaDomain();// 建立非主域var domain = new NatashaDomain(key);// 載入外掛程式var assembly = domain.LoadPlugin(pluginPath);// 使用程式集比較器domain.SetAssemblyLoadBehavior(AssemblyCompareInfomation.UseHighVersion);// 封裝APIdomain.LoadPluginWithHighDependency(PluginPath);

在智慧編譯模式下,你可以使用如下程式碼快速地進行編譯,Natasha將智慧地合並後設資料和Using聲明,並進行語意檢查。

AssemblyCSharpBuilder builder = new AssemblyCSharpBuilder();var myAssembly = builder.UseRandomDomain() .UseSmartMode() .Add("public class A{ }") .GetAssembly();


Natasha的輕便編譯模式

對於更加輕便的編譯需求,Natasha提供了簡潔編譯模式。該模式會合並當前域的後設資料和Using聲明,並關閉語意檢查,提供一種更加靈活快速的編譯方式。

AssemblyCSharpBuilder builder = new AssemblyCSharpBuilder();var myAssembly = builder.UseRandomDomain() .UseSimpleMode() .Add("public class A{ }") .GetAssembly();

後設資料管理與微調

Natasha也提供了完整覆蓋和部份覆蓋參照和using程式碼的能力。例如,合並共享域的參照和using程式碼可以使用以下方法:

builder.WithCombineReferences(item => item.UseAllReferences());builder.WithCombineUsingCode(UsingLoadBehavior.WithAll);

如果希望合並當前域的參照和using程式碼或者使用自訂的參照,可以使用如下方法:

builder.WithCurrentReferences();builder.WithCombineUsingCode(UsingLoadBehavior.WithCurrent);// 使用自訂的後設資料參照builder.WithSpecifiedReferences(someMetadataReferences);

指令碼教程

對於編寫和載入指令碼, Natasha 采用靈活的配置API來覆蓋using程式碼,並添加編譯選項。這允許開發者指定指令碼中要使用的C#語言版本,以及如何處理using指令。

// 配置語言版本builder.ConfigSyntaxOptions(opt => opt.WithLanguageVersion(LanguageVersion.CSharp6));// 添加指令碼並覆蓋Using Codebuilder.WithCombineUsingCode(UsingLoadBehavior.WithAll).Add(myCode);// 自訂覆蓋Using Codebuilder.Add("script", UsingLoadBehavior.WithCurrent);


高級編譯技巧

Natasha 提供了一系列的With、Set和Config系列API來精細控制編譯過程。你可以配置編譯選項、診斷資訊級別,甚至啟用或關閉某些特殊的編譯行為。例如,啟用語意檢查或添加語意處理外掛程式:

// 啟用語意檢查builder.WithSemanticCheck();//增加語意處理外掛程式builder.AddSemanticAnalysistor();

動態 偵錯

使用Natasha進行動態原始碼偵錯是輕而易舉的。開啟偵錯模式可以幫助你更深入地了解程式碼執行情況,Natasha提供了多種選項來寫入偵錯資訊:

builder.WithDebugCompile(item => item.WriteToFile()); // 偵錯資訊寫入檔builder.WithDebugCompile(item => item.WriteToAssembly()); // 偵錯資訊整合到程式集builder.WithReleaseCompile(); // 設定為Release模式

生成程式集

在程式集被編譯前,你可以使用Natasha提供的API來進行各種配置,比如設定程式集名稱或輸出選項:

builder.SetAssemblyName("MyAssembly");builder.WithSemanticCheck(); // 啟用語意檢查builder.WithFileOutput("path/to/dll""path/to/pdb""path/to/xml"); // 檔輸出配置

使用 Codecov 的擴充套件

Natasha 還提供了一個Codecov擴充套件,可幫助你獲取程式碼覆蓋率數據。首先你需要引入 DotNetCore.Natasha.CSharp.Extension.Codecov 擴充套件包,然後像下面這樣使用:

builder.WithCodecov();Assembly asm = builder.GetAssembly();List<(string MethodName, bool[] Usage)>? coverageData = asm.GetCodecovCollection();Show(coverageData);

上面的 Show 方法將遍歷並顯示每個方法的執行情況。這是一種很好的方式來監測你的程式碼如何執行,確保品質和可靠性。


Natasha 的型別擴充套件

最後, Natasha 提供了型別擴充套件來幫助你更輕松地處理型別資訊。例如,獲取執行時或開發時的型別名稱,或者檢查型別是否實作了某個介面:

typeof(Dictionary<string,List<int>>[]).GetRuntimeName(); // 獲取執行時型別名稱typeof(Dictionary<string,List<int>>).IsImplementFrom<IDictionary>(); // 檢查是否實作指定介面

當然這個計畫也是開源的,不論是學習思路還是程式碼設計方案 ,檢視下面的計畫地址都是不錯的選擇

https://github.com/dotnetcore/Natasha

後面我會使用 Natasha 嘗試透過AI來生成c#程式碼並動態執行,可以關註我,並持續關註我的下一步行動!