C# 9: 邁向支持腳本編程的第一步

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

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

C#編譯器目前支持一種可用於各種腳本開發和交互目的的語言方言,使用該方言,可以直接在頂層編寫語句和非虛成員,而不需要使用成員體或類型進行包裝。
雖然腳本方言很少被使用,且在某些方面上,它還沒有跟上“主流”的C #語言,但是通過Try.NET和其他技術的使用場景卻在快速增加,因此我擔心C#未來會出現兩種不兼容的腳本方言。

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

除了Try.NET之外,C#腳本在數據科學和機器學習的使用場景也在增加,而且使用者可以直接從實時數據交互這種模式中受益。
那麼爲什麼不將交互 / C#腳本分開呢?因爲我認爲使代碼能夠在“實驗”和“軟件研發”之間來回切換是非常有價值的。

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

方案1

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

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

譯者注:
方案1中,頂層語句最終會被編譯成如下代碼:
static class Program
{
static async Task Main(string[] args)
{
// 這裏是你定義在命名空間外部的語句
}
}

方案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),編譯輸出的代碼形式只會是以下四種:

static void Main(string[] args)
static int Main(string[] args)
static Task Main(string[] args)
static Task<int> Main(string[] args)

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

原文鏈接:

C# 9: Towards First Class Support for Scripting

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章