跳過到頁腳內容
Iron Academy Logo
學習 C#
學習 C#

其他分類

C# 14 中的新字段關鍵字

C#中的自動屬性簡潔,但當您需要在setter中加入驗證或轉換邏輯時,就不得不完全放棄它們,並撰寫一個具有手動輔助欄位的完整屬性。 從一行跳到七行是為了添加單個保護子句而付出的高昂代價。 C# 14引入field關鍵字來填補這一差距,讓您可以在編譯器仍管理輔助欄位的情況下自訂getter或setter。

在他的影片《C# 14的新field關鍵字》中,Tim Corey展示了這個功能解決的問題,並通過具體的setter驗證範例講解,還介紹了升級前應了解的命名衝突。 我們將詳細遵循每一步驟,以便您可以自信地在自己的屬性中使用field

設置:一個簡單的Person模型

[0:12 - 1:07] Tim從在.NET 10和 Visual Studio 2026上執行的控制台應用程式開始。演示主要聚焦於一個具有若干屬性的Person類:

public required string FirstName { get; set; }
public required string LastName { get; set; }
public int Age { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public int Age { get; set; }

還有一個由私有欄位支援的Demo屬性,當命名衝突出現時變得相關。 在LastName = "Corey"創建一個實例,然後打印姓氏、年齡和演示值。 一切如預期輸出:'Corey',0(默認整數),和 'test'。

問題:自動屬性接受不良數據

[1:23 - 2:49] 問題在於Tim在結構後將LastName時出現:

p.LastName = null;
p.LastName = null;

即使required並被類型定義為不可為空的字串,賦值仍可編譯。 required修飾符僅強制在物件初始化期間提供值; 它不會阻止他人在之後將屬性設置為null。 結果是在運行時出現空白姓氏且未拋錯誤。

這在數據完整性上是一個真正的漏洞。 類型系統會通過可空性引用波浪線警告您,但這僅是編譯時提示而非運行時保護。 如果您的應用程式依賴於LastName始終包含有效字串,僅靠自動屬性無法強制執行該契約。

舊的解決方案:具有手動輔助欄位的完整屬性

[2:58 - 4:19] 在C# 14之前,標準解決方案是將自動屬性轉換為具有顯式輔助欄位的完整屬性:

private string _lastName;
public required string LastName
{
    get => _lastName;
    set => _lastName = value ?? throw new ArgumentNullException(nameof(LastName));
}
private string _lastName;
public required string LastName
{
    get => _lastName;
    set => _lastName = value ?? throw new ArgumentNullException(nameof(LastName));
}

Tim運行這個並確認異常正確地觸發:'值不能為空。 參數名稱:LastName。' 這種方法有效,但它需要聲明一個私有欄位,並連接getter和setter,並在多行中重複屬性名稱。 對於單個驗證規則,這是一種繁鎖的程式。

在這種情況下,getter沒有執行特殊操作; 它不改變地返回欄位的值。 然而您仍必須明確撰寫它,因為一旦您離開自動屬性範疇,語法便要求兩部分同時存在。 Tim將這種繁瑣視為新功能背後的動機。

C# 14解決方案:field關鍵字

[4:23 - 5:47] C# 14引入了一個中間地帶。 不再需要自行聲明私有輔助欄位,您可以在getter或setter中使用上下文關鍵字field來直接引用由編譯器生成的輔助欄位:

public required string LastName
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(LastName));
}
public required string LastName
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(LastName));
}

getter保持為自動實作get;,不需要主體。 setter使用value。 編譯器在幕後創建並管理輔助欄位,就像標準自動屬性一樣。

運行演示在空值賦值時產生同樣的ArgumentNullException。 行為與手動支援版本相同,從七行壓縮到僅自訂所需的精簡區塊。 您保留自動屬性getter,僅在setter中加入邏輯,並完全跳過手動欄位聲明。

這提供了一個實用的中間步驟,介於簡單自動屬性(一行,無驗證)和完整屬性(七行或更多,完全控制)之間。 當您的邏輯僅觸及setter時,您不再需要支付重寫getter的語法代價。

使用Setter保障驗證年齡

[6:16 - 7:39] 為了展示Age屬性添加了範圍驗證:

public int Age
{
    get;
    set
    {
        if (value > 0 && value < 120)
            field = value;
    }
}
public int Age
{
    get;
    set
    {
        if (value > 0 && value < 120)
            field = value;
    }
}

此處setter默默地忽略掉位於合理範圍之外的值。 將field從未被寫入。 Tim指出,您可以拋出異常,但這種靜默方法演示了setter主體可以包含您需要的任何邏輯,同時仍依賴於field進行存儲。

模式廣泛適用:約束數字範圍,修剪字串中的空白,標準化大小寫,或是每次設置屬性時應用的任何轉換。

與現有field變數的命名衝突

[7:39 - 9:43] Tim介紹了一個刻意設置的邊緣案例。 演示類有一個字面名稱為field的私有成員:

private string field = "test";
private string field = "test";

一旦C# 14有效,編譯器將屬性存取器中的field視為關鍵字而非變數。 這意味著參考field的屬性會默默從該屬性後面的隱藏存儲(空的)中讀取,而不是含有'test'的字串成員。 輸出變為空白且無編譯錯誤,僅有警告。

存在兩種解決方案。加上this.field前綴能告訴編譯器您指的是類級成員,而非關鍵字。 或者,@field逃逸符號同樣有效:

// Both refer to the instance variable, not the keyword
string demo => this.field;
string demo => @field;
// Both refer to the instance variable, not the keyword
string demo => this.field;
string demo => @field;

Tim強烈建議在升級到C# 14時重命名任何稱為field的變數。在您的IDE中快速'全部重命名'即可永久消除歧義。 衝突只會在屬性存取器內部發生; 構造函數和方法會將field解析為變數名稱,因為這些上下文中沒有隱式輔助存儲。

總結:更少的樣板,但同樣的控制

[10:04 - 10:28] field關鍵字填補了日常C#程式碼中的一個實用缺口。 需要一個保護子句或轉換的屬性不再需要全面重寫,使用手動輔助欄位。 您只自訂需要邏輯的存取器,而將另一個作為標準自動實作。

結論

[10:28 - 10:35] 回顧:C# 14的field關鍵字為您提供了直接存取任何屬性存取器內隱式輔助存儲的能力。 使用它來添加setter驗證、getter轉換或兩者兼有,而不必為不需要客製化的部分放棄自動屬性語法。

在升級之前,請在您的原始碼庫中搜尋任何名為field的變數並重命名它們。 那樣的小心能避免此功能引入的唯一潛在問題。 除此之外,它是一種乾淨的樣板減少,完全適合大多數開發者已經結構化其模型的方式。

範例提示:如果您只需要驗證setter,則將getter保持為一個沒有主體的普通get;。 編譯器會將其當成自動屬性getter處理,您無需撰寫無意義的傳遞回傳語句。

觀看完整影片在他的YouTube頻道上,並獲得更多關於C#語言功能的見解。

Hero Worlddot related to C# 14 中的新字段關鍵字
Hero Affiliate related to C# 14 中的新字段關鍵字

通過分享您所愛的東西賺得更多

您是否在為使用.NET、C#、Java、Python或Node.js的開發者創建內容?將您的專業知識轉化為額外收入!

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我