Natasha 5.0 版本已於 2022/10/10 日釋出, 此次大版本更迭帶來了相容性支援, 目前 Natasha 可以相容 standard2.0 及 coreapp3.1 以上版本.
下載使用
NuGet\Install-Package DotNetCore.Natasha.CSharp -Version 5.0.0
.
該版本分離了編譯引擎, Natasha 將根據 <TargetFramework> {NET VERSION} </TargetFramework>
目標版本來適配對外的 API.
單域編譯引擎
相容 Standard2.0(Core3.1 以下) 版本, 動態構建將在主域中進行, 您無法體驗到多域程式設計帶來的好處, 也無法解除安裝動態編譯輸出的程式集.
不相容舊版 Natasha API, 舊版 Natasha 僅支援多域程式設計, 並提供了多域方面的 API, 而單域引擎是從多域引擎分離簡化而來, 它將失去一些非必要的 API.
多域編譯引擎
相容 Core3.1 以上版本, 支援程式集解除安裝, 域功能隔離, 外掛載入解除安裝等操作.
相容舊版 Natasha API, 本次升級保留了多域環境應有的 API, 未做改變, .
本次版本在原始碼層,分為 MultiDomain / Public / SingleDomain 三部分, 並使用自定義宏 MULTI
來區分單/多域, 從工程檔案上做相容隔離允許 Natasha 後續的升級工作不必過多的關注相容性程式碼, 多域引擎仍然是 Natasha 未來版本的主戰場, 迭代優化工作將在 MultiDomain 資料夾中進行.
相比較有特色的 API {OperatorClass}.DefaultDomain/CreateDomain/RandomDomain/UseDomain
單域版僅有 {OperatorClass}.DefaultDomain
一個 API, 單域引擎的編譯結果均載入到主域中, 因此也不具備隔離和解除安裝功能.
編譯前提 : 使用 字串指令碼 需要對編譯原理有一定的瞭解, Roslyn 及 Natasha 簡化了複雜的理論依據及構建過程, 使用 Natasha 您只需關注3點:
後設資料管理, 熟悉 Emit / Expression 的同學應該清楚, 在構建過程中可能用到反射, 比如 propertyInfo / fieldInfo / methodInfo, 因為在程式設計中只關注使用,而忽視了後設資料對動態編譯的重要性, 從而切換到字串編譯的時候出現各種各樣的問題, Roslyn 和 Natasha 同樣是需要後設資料的, 而後設資料的來源有 參照程式集,記憶體程式集,實際程式集, 除記憶體程式集外後設資料均記錄在 DLL 檔案中, 因此您可以看到一些構建程式碼是這樣: NatashaManagement.AddGlobalReference("1.dll");
這一步的缺失可能導致錯誤: 找不到 RuntimeMetadataVersion 的值。找不到包含 System.Object 的程式集,或未通過選項為 RuntimeMetadataVersion 指定值。
, 參照管理對程式來講是有一定負擔的, 因為目前還不能從記憶體程式集中提取後設資料, 所以需要以檔案方式來新增, 這也導致你釋出動態編譯的程式時需要有完備的參照檔案跟隨, 因此會導致您釋出的包體積變大, 至於環境需要哪些參照檔案我們交給 DotNetCore.Compile.Environment
環境包來解決, 如果您不能很好的管理參照, 請引入該包全面覆蓋當前程式的後設資料.
Using 管理, 這關乎著後設資料的參照來源, 任何動態構建都是以一個完整類方式進行, 那麼完整的類 using 程式碼是必不可少的一部分, Natasha 的構建模板可以覆蓋大部分 using 並有語意過濾處理異常 using, 如果您直接使用 AssemblyCSharpBuilder
來構建程式碼則需要注意指令碼中的 using 部分.
編譯環境 : 編譯環境包已不在新版的 Natasha 中,推薦使用 Natasha 的 API NatashaManagement.AddGlobalReference/AddGlobalUsing
來管理全域性參照及 Using 快取, 如果您不能很好管理的後設資料參照, 請引入 DotNetCore.Compile.Environment
包來解決後設資料參照的問題.
輸出環境 : 若您覺得生成檔案中有較多的多語言適配, 可以使用 <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
來指定預設的資源語言.
二義性錯誤 : 該問題仍然被歸屬到使用者的錯誤程式設計行為中, 並不該由 IDE 或 Natasha 自動解決, 我仍傾向於在名稱空間發生衝突時由使用者手動改解決該問題, 上下文語意環境不能百分百推測出使用者想使用某個名稱空間.目前推薦的三種方法:
Natasha.CSharp.Extension.Ambiguity
擴充套件包及 .Using()/.ConfigUsing()
模板自帶的方法指定優先順序最高的 Using. (該包將在不久後以獨立專案存在,它並不屬於 Natasha 專案, 晚於 Natasha5.0 釋出)AssemblyCSharpBuilder
編譯字串, 在字串層面替換.assemblyCSharpBuilder.AddSemanticAnalysistor(Func<AssemblyCSharpBuilder, CSharpCompilation, CSharpCompilation>)
(需要有語法語意相關程式設計經驗).一個儘可能複雜的案例:
var action = NDelegate
//使用隨機域 也可以使用 CreateDomain / UseDomain / DefaultDomain
//Core3.1以下僅能使用 DefaultDomain
.DefaultDomain()
//[可選API] 必要時使用 ConfigBuilder 設定編譯單元(下面只為展示API, 有需求就用, 沒需求不用寫)
.ConfigBuilder(builder => builder
//設定編譯器選項
.ConfigCompilerOption(opt => opt
//設定平臺
.SetPlatform(Microsoft.CodeAnalysis.Platform.AnyCpu)
//Release 方式編譯
.CompileAsRelease()
//開啟可空警告
.SetNullableCompile(Microsoft.CodeAnalysis.NullableContextOptions.Warnings))
//設定語法選項
.ConfigSyntaxOptions(opt => opt
//設定支援的指令碼語言版本
.WithLanguageVersion(Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8))
//禁用語意檢查與過濾
.DisableSemanticCheck()
)
//[可選API] 設定該方法所在的類別範本
.ConfigClass(item => item
//給類設定一個名字,不用隨即名
.Name("myClass")
//不使用預設域的 Using 快取
.NoGlobalUsing())
//[可選API] 為類別範本新增 using 參照
.ConfigUsing("System")
//這裡的 API 參照定義的委託, 包括委託的引數
//例如 Action<int> / Func<int,int> 擁有一個引數, 引數的名字請在 Action<int> / Func<int,int> 上 F12 檢視定義獲取引數名.
.Action("Console.WriteLine(\"Hello World!\");");
action(); /*Output: Hello World!*/
IndexOf
替代 Contans
方法做相容.DotNetCore.SourceLink.Environment
依賴以支援 netstandard2.0/1 版本.DotNetCore.Compile.Environment
依賴以支援 netstandard2.0/1 版本.