C#9.0新特性詳解系列之四:頂級程式語句(Top-Level Programs)

碼客風雲發表於2020-12-06

1 背景與動機

通常,如果只想用C#在控制檯上列印一行“Hello World!”,這可不是Console.WriteLine("Hello World!");一條語句就可以搞定的,還涉及到其他必要基礎程式碼(如定義類和入口函式Main),例如下面:

using System;
class Program
{
    static void Main()
    {
        Console.WriteLine("Hello World!");
    }
}

就列印一句“Hello World!”,就這麼多程式碼。這個不僅對於初學者來說麻煩,而且使得程式碼凌亂,並且增加了縮排層級。為了解決這些問題,就提出了頂級程式碼語句這個新特性。

2 頂級語句

2.1 介紹

在C#9.0中,將Class的定義和主函式Main的宣告省略掉,只寫出你的核心業務程式碼,就成了頂級語句。上面這段程式碼,我們可以用頂級語句寫為:

using System;

Console.WriteLine("Hello World!");

這樣,程式碼簡潔清晰了很多,易於初學者理解。是不是有點寫Python的感覺?當然,任何語句都是允許的。如果你想返回值,你可以那樣做;你想用await,也可以那樣做;如果你想訪問命令列引數,args也是可用的;你想使用本地函式,也是可以的。

雖然可以使用任何程式碼,但是有一些規則要求必須遵守:

  • 頂級語句必須放在using語句程式碼後面

  • 頂級語句必須用在任何型別或者名稱空間宣告的前面

  • 頂級語句只能寫在一個原始碼檔案裡,像如今只能寫一個main方法一樣。

  • 頂級語句中定義的本地函式和變數,在頂級程式碼段外部的任何地方呼叫他們都會產生錯誤。

下面這段程式碼就是一個比較好的示例:

using static System.Console;
using System.Threading.Tasks;

WriteLine("Hello,");
Print(args[0]);
await Task.Delay(1000);
return 0;

void Print(string arg)
{
    WriteLine(arg);
}

2.2 原理

我們知道,C#作為物件導向的程式語言,一切型別都是物件導向的,要有型別和成員定義。頂級語句表面看著好像違反了這一規則,實際上沒有。這是因為,頂級語句最終還是在編譯的時候,被作為全域性命空間中Program類的Main方法體中一段程式碼一起自動生成。如下所示:

static class Program
{
    static async Task Main(string[] args)
    {
        // 頂級語句
    }
}

需要注意的是,這裡的類名Program和方法名Main只是用來舉例,其實在編譯器生成的不是這個名字。我們可以通過檢視IL程式碼確認這一點:
IL截圖

根據在頂級語句中是否有非同步操作和返回值的情況,生成的入口函式簽名也是不同的。具體如下面表格所示:

存在返回值 不存在返回值
存在非同步 async static Task<int> Main(string[] args) async static Task Main(string[] args)
不存在非同步 static int Main(string[] args) static void Main(string[] args)

例如上面程式碼,生成的入口函式<Main>$就如下程式碼所示:

static class Program
{
    async static Task<int> Main(string[] args)
    {
        WriteLine("Hello");
        Print(args[0]);
        await Task.Delay(1000);
        return 0;

        void Print(string arg)
        {
            WriteLine(arg);
        }
    }
}

3 結束語

使用頂級語句能簡化我們的編碼工作,使程式碼看起來簡潔清晰,對初學者也很友好,本質上也未改變C#的語言的原有的語法結構,任何語句都可以使用,沒有產生額外的限制,從這些方面來說,是一個值得肯定的變化。

如對您有價值,請推薦,您的鼓勵是我繼續的動力,在此萬分感謝。關注本人公眾號“碼客風雲”,享第一時間閱讀最新文章。

碼客風雲

 

相關文章