java程序員,看到C#程序員要膜拜了。驚!C# 9.0 支持腳本編程

不需要任何樣板代碼是腳本語言的一個顯著特徵,你可以直接在文件的第一行編寫聲明和語句,就像在函數內部一樣。相反,諸如 VB,C#或者 Java 之類的非腳本語言,在類文件中就必須包含類似“main”方法的樣板代碼。

微軟的 C#開發經理 Mads Torgersen 在 3117 提案中建議 C# 9 支持頂層語句和函數的功能。該提案允許在文件中直接編寫語句和函數,而無需使用類(Class)進行包裝。Torgersen 聲稱該提案的初衷是:

C#編譯器目前支持一種可用於各種腳本開發和交互目的的語言方言,使用該方言,可以直接在頂層編寫語句和非虛成員,而不需要使用成員體或類型進行包裝。

雖然腳本方言很少被使用,且在某些方面上,它還沒有跟上“主流”的 C #語言,但是通過 Try.NET 和其他技術的使用場景卻在快速增加,因此我擔心 C#未來會出現兩種不兼容的腳本方言。

雖然當前版本的 C#腳本還沒有被廣泛使用,但 Torgersen 預測未來這個局面會被打破:

除了 Try.NET 之外,C#腳本在數據科學和機器學習的使用場景也在增加,而且使用者可以直接從實時數據交互這種模式中受益。

那麼為什麼不將交互 / C#腳本分開呢?因為我認為使代碼能夠在“實驗”和“軟件研發”之間來回切換是非常有價值的。

Torgersen 認為以下三種方案, 都可以實現頂層語句 / 函數的功能:

方案 1

如果採納該方案,那麼執行語言將被允許出現在命名空間聲明之前。這些執行語句將被編譯到一個主函數內,然後該主函數會被放到一個程序(Program)類中,該主函數可支持異步操作。

如果多個文件都在命名空間的外部聲明瞭執行語句,那麼編譯器會報錯,除非你希望擁有多個包含主函數的程序類。

<code>譯者注:
方案 

1

中,頂層語句最終會被編譯成如下代碼:

static

class

Program

{

static

async

Task

Main

(

string

[] args) { } }/<code>

方案 2

方案 2 是實現頂層函數,該方案允許在命名空間內或者全局定義函數,儘管公開函數也是允許的,但這些函數將被默認當作內部函數。從調用者角度來看,這些函數將直接屬於該命名空間(這也是 VB 模塊中函數的工作原理)。

方案 2 可能的實現思路是,生成一個局部類,將這些成員包裝成靜態成員。這個局部類的名稱不是特定某個名字,可能是在確保不同程序集的相同命名空間中,通過某種方式生成的不重複的名稱。只要頂層成員中有一個是公共的,那麼這個局部類就是公共的,通過這種方式,可以讓程序集知道那些成員是可以直接對外暴露的。

方案 3

雖然現有的 C#腳本方言和 C#本身是 2 種不同的語言,但方案 3 目的不是消除腳本方言,而是為了讓這 2 種語言結合的更加緊密。Torgersen 說到:

如果在 C#中添加對頂層語句和函數的支持,那麼我們不希望頂層語句和函數的執行和其在腳本中執行有衝突。相反,在保持語義功能一致的前提下,我們希望在必要的時候,以某種方式對它們進行必要的編譯。這並不會完全消除腳本語言,因為我們仍然需要處理它們所依賴的特殊指令和“魔法命令”。但至少我們可以避免相同的語法表達不同的邏輯。

目前,Mads 建議 C#只關注方案 1,他說到:

你可以大膽的想象下,要實現一個滿足所有方案功能,將會是怎樣。那將需要進行大量的設計, 考慮大量的細節,因此我不建議這樣做,相反,我認為我們應該關注在方案 1 的實現上。因為本質上,方案 1 其實已經基本包含了其他方案。

同時他提到,在使用方案 1 實現任何功能的時候,將來都不會給實現方案 2 和方案 3 帶來困擾。

設計細則

頂層語句的第一條規則是,項目中只允許一個文件存在頂層語句。就像只能有一個“Main”函數一樣,如果在一個文件中包含多個 naked 語句,那麼編譯器會報錯。

語句的內容決定了最終編譯產生的代碼形式。無論語句是否使用了 await 關鍵字或者是否有 return 表達式(例如:return 5),編譯輸出的代碼形式只會是以下四種:

<code>

static

void

Main

(

string

[] args)

static

int

Main

(

string

[] args)

static

Task

Main

(

string

[] args)

static

Task<

int

>

Main

(

string

[] args)/<code>

支持相同的語法,就像普通方法中使用本地函數一樣。


分享到:


相關文章: