C# 9 新特性:代码生成器、编译时反射
前言
今天 .NET 官方博客宣布 C# 9 Source Generators 第一個預覽版發(fā)布,這是一個用戶已經(jīng)喊了快 5 年特性,今天終于發(fā)布了。
簡介
Source Generators 顧名思義代碼生成器,它允許開發(fā)者在代碼編譯過程中獲取查看用戶代碼并且生成新的 C# 代碼參與編譯過程,并且可以很好的與代碼分析器集成提供 Intellisense、調(diào)試信息和報錯信息,可以用它來做代碼生成,因此也相當于是一個加強版本的編譯時反射。
使用 Source Generators,可以做到這些事情:
獲取一個 Compilation 對象,這個對象表示了所有正在編譯的用戶代碼,你可以從中獲取 AST 和語義模型等信息
可以向 Compilation 對象中插入新的代碼,讓編譯器連同已有的用戶代碼一起編譯
Source Generators 作為編譯過程中的一個階段執(zhí)行:
編譯運行 -> [分析源代碼 -> 生成新代碼] -> 將生成的新代碼添加入編譯過程 -> 編譯繼續(xù)。
上述流程中,中括號包括的內(nèi)容即為 Source Generators 所參與的階段和能做到的事情。
作用
.NET 明明具備運行時反射和動態(tài) IL 織入功能,那這個 Source Generators 有什么用呢?
編譯時反射 - 0 運行時開銷
拿 ASP.NET Core 舉例,啟動一個 ASP.NET Core 應用時,首先會通過運行時反射來發(fā)現(xiàn) Controllers、Services 等的類型定義,然后在請求管道中需要通過運行時反射獲取其構造函數(shù)信息以便于進行依賴注入。然而運行時反射開銷很大,即使緩存了類型簽名,對于剛剛啟動后的應用也無任何幫助作用,而且不利于做 AOT 編譯。
Source Generators 將可以讓 ASP.NET Core 所有的類型發(fā)現(xiàn)、依賴注入等在編譯時就全部完成并編譯到最終的程序集當中,最終做到 0 運行時反射使用,不僅利于 AOT 編譯,而且運行時 0 開銷。
除了上述作用之外,gRPC 等也可以利用此功能在編譯時織入代碼參與編譯,不需要再利用任何的 MSBuild Task 做代碼生成啦!
另外,甚至還可以讀取 XML、JSON 直接生成 C# 代碼參與編譯,DTO 編寫全自動化都是沒問題的。
AOT 編譯
Source Generators 的另一個作用是可以幫助消除 AOT 編譯優(yōu)化的主要障礙。
許多框架和庫都大量使用反射,例如System.Text.Json、System.Text.RegularExpressions、ASP.NET Core 和 WPF 等等,它們在運行時從用戶代碼中發(fā)現(xiàn)類型。這些非常不利于 AOT 編譯優(yōu)化,因為為了使反射能夠正常工作,必須將大量額外甚至可能不需要的類型元數(shù)據(jù)編譯到最終的原生映像當中。
有了 Source Generators 之后,只需要做編譯時代碼生成便可以避免大部分的運行時反射的使用,讓 AOT 編譯優(yōu)化工具能夠更好的運行。
例子
INotifyPropertyChanged
寫過 WPF 或 UWP 的都知道,在 ViewModel 中為了使屬性變更可被發(fā)現(xiàn),需要實現(xiàn)?INotifyPropertyChanged?接口,并且在每一個需要的屬性的?setter?處除法屬性更改事件:
當屬性多了之后將會非常繁瑣,先前 C# 引入了?CallerMemberName?用于簡化屬性較多時候的情況:
即,用?CallerMemberName?指示參數(shù),在編譯時自動填充調(diào)用方的成員名稱。
但是還是不方便。
如今有了 Source Generators,我們可以在編譯時生成代碼做到這一點了。
為了實現(xiàn) Source Generators,我們需要寫個實現(xiàn)了?ISourceGenerator?并且標注了?Generator?的類型。
完整的 Source Generators 代碼如下:
有了上述代碼生成器之后,以后我們只需要這樣寫 ViewModel 就會自動生成通知接口的事件觸發(fā)調(diào)用:
上述代碼將會在編譯時自動生成以下代碼參與編譯:
非常方便!
使用時,將 Source Generators 部分作為一個獨立的 .NET Standard 2.0 程序集(暫時不支持 2.1),用以下方式引入到你的項目即可:
限制
Source Generators 僅能用于訪問和生成代碼,但是不能修改已有代碼,這有一定原因是出于安全考量。
文檔
Source Generators 處于早期預覽階段,docs.microsoft.com 上暫時沒有相關文檔,關于它的文檔請訪問在 roslyn 倉庫中的文檔:
設計文檔
使用文檔
后記
目前 Source Generators 仍處于非常早期的預覽階段,API 后期還可能會有很大的改動,因此現(xiàn)階段不要用于生產(chǎn)。
另外,關于與 IDE 的集成、診斷信息、斷點調(diào)試信息等的開發(fā)也在進行中,請期待后續(xù)的 preview 版本吧。
總結(jié)
以上是生活随笔為你收集整理的C# 9 新特性:代码生成器、编译时反射的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从GC的SuppressFinalize
- 下一篇: C#并发编程之初识并行编程