基于roslyn的动态编译库Natasha
?
?
人老了,玩不轉(zhuǎn)博客園的編輯器,詳細信息轉(zhuǎn)到:https://mp.weixin.qq.com/s/1r6YKBkyovQSMUgfm_VxBg
?
?
?
關鍵字:Github, NCC, Natasha,Roslyn, .NET Core2.0,.NET Core2.1,.NET Core2.2,.NET Core2.3, standard2.0, 動態(tài)編譯,運行時腳本,高性能。
?一、 前言
?
????????對于開源貢獻者,Emit和表達式樹不是陌生的字眼,IL的動態(tài)特性為封裝工作帶來了極大的方便,會Emit的開發(fā)者可以說駕馭了大部分的高性能、高動態(tài)的編程技巧。縱觀ef、dapper、json.net等第三方常用庫,哪個能脫離emit而獨善其身,也正因如此,幸福了一批批懶癌患者,包括我這個懶癌中晚期患者(這里給各位病友問好),與此同時本人對封裝有著莫名其妙的執(zhí)念,就在兩支怪力的驅(qū)使下走上了對emit的不歸路.
?
舊版Natasha始于2016年,當時是對Emit進行的封裝,中途經(jīng)有檸檬的提醒完善了UT和兼容性等工作,后由Victor.X.Qu補充了文檔,后經(jīng)ORM實戰(zhàn)。
?
?
二、Emit非銀彈
?
????????經(jīng)歷過重重思考和實踐,Emit不是動態(tài)的最佳實踐,簡單的從以下幾個角度來講:
?
-
調(diào)優(yōu):
-
?
-
dup?: emit中的dup指令優(yōu)化在是由開發(fā)者控制的,在熟悉指令操作的同時又給開發(fā)者帶來了額外的優(yōu)化工作。
?
-
if/while/for?:不得不說IL可以透過代碼看本質(zhì),指令就是這樣的,在條件分支上,標簽跳轉(zhuǎn)的形式使得邏輯執(zhí)行靈活多變。這樣除了棧的操作之外,還要關注標簽的位置和跳轉(zhuǎn)語句的優(yōu)化,另外還要清晰的記得你的各個分支。
?
-
并發(fā)字典與算法優(yōu)化?:這一點是出自我的極端,在對象成員的賦值/加載等操作面前,并發(fā)字典像是一場災難,賣盡氣力優(yōu)化的動態(tài)執(zhí)行,卻被某些數(shù)據(jù)結(jié)構(gòu)所糟蹋。至于算法與動態(tài)編譯結(jié)合起來,應該沒幾個病友做過,各位如果有興趣的話可以慢慢體會。
?
-
?
-
兼容性:
-
?
-
結(jié)構(gòu)體?: 類與結(jié)構(gòu)體在操作指令上有著諸多的不同,開發(fā)者不僅僅要熟悉對類的操作指令,還要對結(jié)構(gòu)體做出兼容,諸如ldflda、 ldloca、Constrained等指令,對于開發(fā)者來說并不是一件省心的事。
?
-
類型轉(zhuǎn)換?: .NET中的類型轉(zhuǎn)換不僅僅有指令級的轉(zhuǎn)換,standard還提供了諸多方法支持不同類型之間的轉(zhuǎn)換,因此你還需要花一些功夫去處理這些。
?
-
語法糖?: 一切語法糖在emit面前都要還原,比如可空類型語法糖,對象比較語法糖,類型比較語法糖等等,無疑會大大增加兼容工作的負擔(core3.0的可空引用我還沒有做測試)。
?
-
?
-
構(gòu)建難度:
-
?
-
深度克隆?: 深度克隆是動態(tài)編程的一個典型實戰(zhàn),如果各位病友堅持用EMIT挑戰(zhàn)的話,可以沒病走兩步,走兩步。
?
-
深度構(gòu)建?:一旦遇到了動態(tài)構(gòu)建動態(tài)場景,那么這個復雜度難以想象。
?
-
猜錯誤?: Emit并沒有很好的友情提示,沒有語法檢查,而被程序鍛煉成老獵手一定要付出很多代價。
?
-
?
-
維護升級:
-
?
-
后續(xù)開發(fā)?:接手emit代碼是一件令人糾結(jié)的事,當量變引起質(zhì)變的時候,從興奮到苦不堪言這種事情并不是沒有發(fā)生過,尤其是現(xiàn)在.NET開源工作者都比較獨立,沒有凝聚力和氛圍,人的生命以及精力是有限的。
?
-
傳承??:由上面諸多信息也可見,在新技術的沖擊下,在令人不安的環(huán)境下,在孤獨的夜里,傳承也是個問題。
?
-
?
?
盡管表達式樹已經(jīng)幫我們做了一些工作,但復雜場景和使用習慣仍然封印著開發(fā)者的大腦。
?
?
三、狙擊暴君
?
??????? Roslyn到如今已經(jīng)耳熟能詳了,編譯被當作成服務對外開放,讓不少開發(fā)者從中受益,但由于文檔不全,實例不充分,從開始一直到2018年期間,對于懶癌開發(fā)者來說,基于Roslyn開發(fā)都是一件憋手的事情(例如一些必備操作文檔,在2019年今年5月份才提上日程)。Natasha使用Roslyn做為編譯引擎,不僅僅在動態(tài)構(gòu)建上進行了人性化升級,還在功能上進行了簡化。您不僅可以使用Natasha輕松的構(gòu)建類、結(jié)構(gòu)體、方法、接口、抽象類,還可以輕松的繼承類、重載方法、實現(xiàn)接口、抽象類等等,技術較新,僅支持.standard2.0。
?
????????項 目 地 址:https://github.com/dotnetcore/Natasha
??????? Nuget索引:DotNetCore.Natasha ?(正式版1.0.0.0)
?
(娜塔莎)(原型蘇聯(lián)紅軍第25步兵師的中尉柳德米拉·帕夫利琴科,一名出色的女狙擊手)
?
?
使用Natasha你需要關注:
?
在您的工程文件里添加這個節(jié)點:<PreserveCompilationContext>true</PreserveCompilationContext>
?
了解wiki中反解器的概念及使用。? ??
?
注意命名空間,自動補充命名空間目前尚未支持,需要您手動操作,使用using方法添加。
?
想盡一切辦法拼接字符串,目前符合CSharp7.3或以下C#版本的都行。
?
編譯模式有區(qū)分:StreamComplier內(nèi)存流編譯/FileComplier文件流編譯, 文件流編譯的內(nèi)容,可以被動態(tài)調(diào)用。當你想動態(tài)編譯類B的時候使用類A,那類A就需要使用文件流編譯,相當于dll動態(tài)加載到運行時。
?
使用Natasha中的Operator來構(gòu)建你的動態(tài)內(nèi)容。
?
四、性能
?
????????這幾年隨著.NET架構(gòu)引擎的不斷升級,dynamic、emit執(zhí)行性能已經(jīng)得到了大幅度提升,roslyn也不例外,之前官方給過性能測試截圖,上面顯示是比emit快一點,個人的基準測試要等下一個benchmark版本,從耗時的角度來說roslyn <= emit (roslyn有指定release模式編譯),所以大家根本不用關心性能問題。
?
?
五、使用案例
?
轉(zhuǎn)載于:https://www.cnblogs.com/NMSLanX/p/11284573.html
總結(jié)
以上是生活随笔為你收集整理的基于roslyn的动态编译库Natasha的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: F#学习之路(2) 深刻理解函数(上)
- 下一篇: 显示地图