dotnet C# 如何在頂級語句定義屬性

lindexi發表於2024-08-30

隨著 dotnet 6 開始,現在的 C# dotnet 可以使用頂級語句非常方便建立一個小型專案,包含的程式碼也特別少。本文將和大家介紹如何在頂級語句裡面定義屬性

如以下程式碼是傳統的控制檯應用程式的程式碼

using System;

namespace Application
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

可以看到即使是一個簡單的應用,也需要不少的程式碼。在 dotnet 6 開始,咱可以使用非常方便的頂級語句代替以上程式碼的功能,只需一句程式碼即可

Console.WriteLine("Hello World!");

詳細請看 頂級語句 - C# 教程 - C# - Microsoft Learn

然而有些時候,咱需要定義一些屬性用來輔助某些特定的業務,卻會發現在頂級語句裡面定義方法很簡單,但是定義屬性卻報錯

如以下程式碼將不能透過構建

Foo = "Hello, World!";

Console.WriteLine(Foo);

static string Foo { set; get; }

錯誤提示內容如下

error CS0116: 名稱空間不能直接包含欄位、方法或語句之類的成員

解決方法是寫一個名為 Program 的 partial 類,程式碼如下

partial class Program
{

}

在 Program 裡面定義屬性是非常正確的,修改之後的程式碼如下

Foo = "Hello, World!";

Console.WriteLine(Foo);

partial class Program
{
    public static string Foo { set; get; }
}

以上程式碼是可以透過構建的。其根本原因是頂級語句只是一個語法層面的功能,構建之後的程式碼全部都會被放入到名為 Program 的型別的 Main 方法裡面

回顧一開始最簡短的如下一句程式碼的頂級語句

Console.WriteLine("Hello World!");

其構建出來的程式碼對應的低階 C# 大概如下

using System;
using System.Runtime.CompilerServices;

[CompilerGenerated]
internal class Program
{
  private static void <Main>$(string[] args)
  {
    Console.WriteLine("Hello, World!");
  }

  public Program()
  {
    base..ctor();
  }
}

如此可以看到實際上是生成了一個名為 Program 的型別。這時候再寫一個 partial 的 Program 就可以與生成的 Program 類合併

換句話說,如下程式碼也是完全可以構建透過的

var program = new Program();

Console.WriteLine("Hello, World!");

即不需要手動定義 Program 類,即可使用自動生成的 Program 型別

利用自動生成的 Program 類新增屬性,從而被頂級語句方便的訪問到,這就是在頂級語句裡面新增屬性的核心實現原理

Foo = "Hello, World!";

Console.WriteLine(Foo);

partial class Program
{
    public static string Foo { set; get; }
}

以上程式碼的對應的低階 C# 程式碼大概如下

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

internal class Program
{
  [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  private static string <Foo>k__BackingField;

  private static void <Main>$(string[] args)
  {
    Program.Foo = "Hello, World!";
    Console.WriteLine(Program.Foo);
  }

  public static string Foo
  {
    [CompilerGenerated]
    set
    {
      Program.<Foo>k__BackingField = value;
    }
    [CompilerGenerated]
    get
    {
      return Program.<Foo>k__BackingField;
    }
  }

  public Program()
  {
    base..ctor();
  }
}

由於頂級語句是將程式碼放入到名為 Program 類裡面,此時即可透過再寫一個 partial 的 Program 用來定義屬性,就可以在構建時自動被合入到生成的類裡面

可以看到寫到一個檔案裡面的 Foo 屬性在構建的時候被和頂級語句合併到一起,如此的程式碼可以做到看起來十分簡單,且不會丟失屬性的功能

額外說明一下的是這裡定義的屬性只能的靜態的,在頂級語句裡面,除非構建 Program 的例項,否則將無法直接訪問到屬性

如此即可實現在頂級語句裡面定義屬性

本文程式碼放在 githubgitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快

先建立一個空資料夾,接著使用命令列 cd 命令進入此空資料夾,在命令列裡面輸入以下程式碼,即可獲取到本文的程式碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 082e98d35ef7f959057b76e1f70010651fa18713

以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令列繼續輸入以下程式碼,將 gitee 源換成 github 源進行拉取程式碼。如果依然拉取不到程式碼,可以發郵件向我要程式碼

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 082e98d35ef7f959057b76e1f70010651fa18713

獲取程式碼之後,進入 Workbench/DawkuhelwhehairallweeFewewoyelfalar 資料夾,即可獲取到原始碼

更多技術部落格,請參閱 部落格導航

相關文章