日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Natasha 4.0 探索之路系列(三) 基本的动态编译

發(fā)布時間:2023/12/4 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Natasha 4.0 探索之路系列(三) 基本的动态编译 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

相關(guān)文章

  • Natasha 4.0 探索之路系列(一) 概況

  • Natasha 4.0 探索之路系列(二) 「域」與插件

Natasha 的設(shè)計

動態(tài)編譯

Roslyn 為開發(fā)者提供了動態(tài)編譯的接口,允許我們以 C# 代碼來編寫 Emit 或 表達(dá)式樹生成的程序集,但是完成一個編譯需要諸多步驟,用戶參與的操作也很多,例如: 格式化整理語法樹,創(chuàng)建編譯選項,填充對應(yīng)的引用程序集來支持語義檢查和編譯,控制輸出流等。其中除了第一個語法樹相對簡單,后面都需要開發(fā)者摸索完成。畢竟 Roslyn 的文檔不全,甚至關(guān)于它的文檔散落在其他邊角章節(jié),比七龍珠都散。那么在這種情況下使用 Natasha 無疑是非常好的選擇。

Natasha 的便捷之處

Natasha 自發(fā)版以來,便集成有引用管理,全局 Using 管理,域管理,這讓開發(fā)者極大的減少了開發(fā)前的準(zhǔn)備工作,在便捷編譯過程中,Natasha 支持引用覆蓋,Using 覆蓋,編譯流到域的輸出,有了這三大保證,開發(fā)者可更多的關(guān)注于動態(tài)功能邏輯的開發(fā)。新版 Natasha 新增了語義過濾委托 API 以方便用戶根據(jù)語義信息定制/重組自己的語法樹,并提供方法支持開發(fā)者管理引用版本,另外保證了3種流的對外輸出,即

  • dll : 程序集輸出文件

  • pdb : 元數(shù)據(jù)調(diào)試信息

  • xml : 元數(shù)據(jù)結(jié)構(gòu)及注釋

整個編譯過程中將會分3階段拋出異常:

  • 語法構(gòu)建階段,如果出錯則拋出異常;

  • 編譯階段,如果編譯失敗則會拋出異常;

  • 元數(shù)據(jù)轉(zhuǎn)換階段,有些 API 是支持從 Assembly 到其他元數(shù)據(jù)獲取和轉(zhuǎn)換的,轉(zhuǎn)換失敗則拋出異常。

  • Natasha 基本編譯單元

    Natasha 的基本編譯單元為 AssemblyCSharpBuilder ,該單元整合了編譯流程所需要的基本功能,相比 Natasha 的模板而言,它則是輕量級,底層的工作單元。以下是使用方法:

    首先引入 DotNetCore.Natasha.CSharp

    最基本的編譯操作
    //Natasha 預(yù)熱 NatashaInitializer.Preheating(/*...引用添加過濾器...例如:(item,name) => name!.Contains("IO")*/);string code = @"public class A{public string Name=""HelloWorld"";}";//在花括號范圍內(nèi)圈定域,using 內(nèi)的方法鎖定了域的作用范圍. //Natasha 所有關(guān)于 Name 的 Api 如果不指定,默認(rèn)為 GUID. using (DomainManagement.Create(domainName)/Random().CreateScope()) {AssemblyCSharpBuilder builder = new( /*....assenblyName....*/ );builder.Add(code);var type = builder.GetTypeFromShortName("A"); //...do sth..。 }//手動指定域 AssemblyCSharpBuilder builder = new(); builder.Domain = DomainManagement.Random(); builder.Add(code); var assembly = builder.GetAssembly(); //...do sth..。//直接定位到委托 string code = @"public class A{public string Name=""HelloWorld""; public static string Get(){ return (new A()).Name; }}"; using (DomainManagement.Create("myDomain").CreateScope()) {AssemblyCSharpBuilder builder = new("myAssembly");builder.Add(code);var func = builder.GetDelegateFromShortName<Func<string>>("A","Get");Assert.Equal("HelloWorld",func()); // √ }
    其他 API
    //設(shè)置輸出 dll 文件路徑 builder.SetDllFilePath(mydll); //設(shè)置輸出 pdb 文件路徑 builder.SetPdbFilePath(mypdb); //設(shè)置輸出 xml 文件路徑 builder.SetXmlFilePath(myxml); //使用 Natasha 自帶的輸出路徑(請在域和程序集名確定之后調(diào)用). builder.UseNatashaFileOut();//配置編譯選項 builder.ConfigCompilerOption(opt=>opt); //配置語法樹選項 builder.ConfigSyntaxOptions(opt=>opt);//給編譯單元添加語義過濾 builder.AddSemanticAnalysistor(); //啟/禁用語義過濾 builder.Enable/DisableSemanticCheck();//添加日志事件 builder.LogCompilationEvent += (log) => { if(log.HasError) Console.WriteLine(log.ToString()); };//編譯事件 builder.CompileSucceedEvent //編譯成功觸發(fā)事件 builder.CompileFailedEvent //編譯失敗觸發(fā)事件//引用行為與程序集加載行為控制 var assembly = builder//委托過濾: 如果發(fā)現(xiàn)默認(rèn)域的引用與定制域中的引用有同名情況,則進(jìn)入委托處理。返回一個枚舉結(jié)果給程序處理.//PassToNextHandler 結(jié)果表示將進(jìn)入到引用版本行為控制繼續(xù)處理.CompileWithReferencesFilter((defaultAssemblyName,domainAssemblyName)=> LoadVersionResultEnum.PassToNextHandler)//引用行為控制,None/UseHighVersion/UseLowVersion/UseDefault(默認(rèn)使用)/UseCustom 四種控制方法.CompileWithReferenceLoadBehavior(referenceLoadBehavior)//程序集編譯成功后,在域中加載的行為控制,默認(rèn)為 LoadBehaviorEnum.None (全加載);.CompileWithAssemblyLoadBehavior(LoadBehaviorEnum.UseDefault).GetAssembly();

    注意: 主域的引用文件和自己創(chuàng)建域的引用文件可能存在同名,但不同版本,此時編譯需要 CompileWithReferenceLoadBehavior 來控制引用加載的行為,舉例:RefA(v1.0) 和 RefA(v2.0) 相比,v2.0 中比 v1.0 多了幾個功能,幾個類、幾個接口……那么在管理引用的時候,你就要根據(jù)自身的代碼情況進(jìn)行管理,比如你的代碼用到了 v2.0 的新類,新功能,那么就要屏蔽掉 v1.0。

    覆蓋全局 using
    //-------------------主域 using -------------------- 定制域 using ------------------------------- 代碼腳本 --------------- string code = DefaultUsing.UsingScript + builder.Domain.UsingRecorder.ToString() + "namespace{ public class xx....。}";

    域中的 UsingRecorder 會記錄編譯之后產(chǎn)生的 using,自動管理。

    結(jié)尾

    大家在使用動態(tài)編譯時,要盡可能做到“隔離”,一旦依賴和引用版本多了,對于動態(tài)開發(fā)來講,就是一場災(zāi)難。以上是使用 Natasha 關(guān)于動態(tài)編譯的最基本使用方法,下一篇將講解 Natasha 高級 API 的使用。

    總結(jié)

    以上是生活随笔為你收集整理的Natasha 4.0 探索之路系列(三) 基本的动态编译的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。