C# 9.0 终于来了, Top-level programs 和 Partial Methods 两大新特性探究
一:背景
1. 講故事
.NET 5 終于在 6月25日 發(fā)布了第六個預覽版,隨之而來的是更多的新特性加入到了 C# 9 Preview 中,這個系列也可以繼續(xù)往下寫了,廢話不多說,今天來看一下?Top-level programs?和?Extending Partial Methods?兩大新特性。
2. 安裝必備
下載最新的?.net 5 preview 6。
下載最新的?Visual Studio 2019 version 16.7 Preview 3.1
二:新特性研究
1. Top-level programs
如果大家玩過 python,應(yīng)該知道在 xxx.py 中寫一句 print,這程序就能跑起來了,簡單高效又粗暴,很開心的是這特性被帶到了C# 9.0 中。
修改前
修改后
這就有意思了,Main入口函數(shù)去哪了?沒它的話,JIT還怎么編譯代碼呢?想知道答案的話用 ILSpy 反編譯看一下就好啦!
.class private auto ansi abstract sealed beforefieldinit $Programextends [System.Runtime]System.Object {.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (01 00 00 00)// Methods.method private hidebysig static void $Main (string[] args) cil managed{// Method begins at RVA 0x2050// Code size 18 (0x12).maxstack 8.entrypointIL_0000: ldstr "Hello World!"IL_0005: call void [System.Console]System.Console::WriteLine(string)IL_000a: nopIL_000b: call string [System.Console]System.Console::ReadLine()IL_0010: popIL_0011: ret} // end of method $Program::$Main} // end of class $Program從 IL 上看,類變成了?$Program, 入口方法變成了?$Main, 這就好玩了,在我們的印象中入口函數(shù)必須是?Main,否則編譯器會給你一個大大的錯誤,你加了一個 $ 符號,那CLR還能認識嗎?能不能認識我們用 windbg 看一些托管和非托管堆棧,看看有什么新發(fā)現(xiàn)。
0:010> ~0s ntdll!NtReadFile+0x14: 00007ffe`f8f8aa64 c3 ret 0:000> !dumpstack OS Thread Id: 0x7278 (0) Current frame: ntdll!NtReadFile + 0x14 Child-SP RetAddr Caller, Callee 0000008551F7E810 00007ffed1e841dc (MethodDesc 00007ffe4020d500 + 0x1c System.Console.ReadLine()), calling 00007ffe400ab090 0000008551F7E840 00007ffe4014244a (MethodDesc 00007ffe401e58f0 + 0x3a $Program.$Main(System.String[])), calling 00007ffe40240f58 0000008551F7E880 00007ffe9fcc8b43 coreclr!CallDescrWorkerInternal + 0x83 [F:\workspace\_work\1\s\src\coreclr\src\vm\amd64\CallDescrWorkerAMD64.asm:101] 0000008551F7E8C0 00007ffe9fbd1e03 coreclr!MethodDescCallSite::CallTargetWorker + 0x263 [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:554], calling coreclr!CallDescrWorkerWithHandler [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:56] 0000008551F7E950 00007ffe9fb8c4e5 coreclr!MethodDesc::IsVoid + 0x21 [F:\workspace\_work\1\s\src\coreclr\src\vm\method.cpp:1098], calling coreclr!MetaSig::IsReturnTypeVoid [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp:5189] 0000008551F7EA00 00007ffe9fb8c4bf coreclr!RunMainInternal + 0x11f [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1488], calling coreclr!MethodDescCallSite::CallTargetWorker [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:266] 0000008551F7EB30 00007ffe9fb8c30a coreclr!RunMain + 0xd2 [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1559], calling coreclr!RunMainInternal [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1459]從上面堆棧的流程圖看:?coreclr!RunMain?->?coreclr!MethodDesc?->?coreclr!CallDescrWorkerInternal?->?$Program.$Main, 確實被調(diào)用了,不過有一個重大發(fā)現(xiàn),在?$Program.$Main?調(diào)用之前底層的 CLR 讀取了 方法描述符,這就是一個重大突破點,方法描述符在哪里呢?可以用 ildasm 去看一下元數(shù)據(jù)列表。
可以看到,入口函數(shù)那里打上了一個?ENTRYPOINT?標記,這就說明入口函數(shù)名其實是可以隨便更改的,只要被?ENTRYPOINT打上標記即可,CoreCLR就能認的出來~~~
2. Partial Methods
我們知道 部分方法 是一個很好的樁函數(shù),而且在 C# 3.0 中就已經(jīng)實現(xiàn)了,那時候給我們增加了很多限制,如下圖:
翻譯過來就是:
部分方法的簽名必須一致
方法必須返回void
不允許使用訪問修飾符,而且還是隱式私有的。
在 C# 9.0 中放開了對 方法簽名 的所有限制,正如 issue 總結(jié):
這是一個非常好的消息,現(xiàn)在你的部分方法上可以加上各種類型的返回值啦,這里我舉一個例子:
class Program{static void Main(string[] args){var person = new Person();Console.WriteLine(person.Run("jack"));}}public partial class Person{public partial string Run(string name);}public partial class Person{public partial string Run(string name) => $"{name}:開溜了~";}然后我們用 ILSpy 簡單看看底層怎么玩的,如下圖可以看到其實就是一個簡單的合成,對吧。
現(xiàn)在我有想法了,如果我不給 Run 方法實現(xiàn)會怎么樣?把下面的 partial 類注釋掉看一下。
從報錯信息看,可訪問的修飾符必須要有方法實現(xiàn),還以為直接編譯的時候抹掉呢。?這就起不到樁函數(shù)的作用:-D,不過這個特性還是給了我們更多的可能用的到的應(yīng)用場景吧。
三:總結(jié)
本篇兩個特性還是非常實用的,Top-level programs 讓我們可以寫更少的代碼,甚至拿起 記事本 都可以快捷的編寫類似一次性使用的測試代碼, Partial Methods 特性留給大家補充吧,我基本上算是沒用過 (┬_┬)。
總結(jié)
以上是生活随笔為你收集整理的C# 9.0 终于来了, Top-level programs 和 Partial Methods 两大新特性探究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Unit Testing》1.4. 成
- 下一篇: [Mvp.Blazor] 集成Ids4,