跳至頁尾內容
Iron Academy Logo
學習C#
學習C#

其他類別

C#中元組的簡介,十分鐘內了解

[[academy-video-youtube({"vid": "QC6hpl2iU0c", "start_time": "0", "title": "Intro to Tuples in C# In 10 Minutes or Less", "creator": "Tim Corey", "length": "9m 49s"})]]

C# 方法設計是圍繞單一返回值進行的,這在一個返回值不夠的情況下會發生問題。 地址驗證是一個典型例子:您需要知道輸入是否有效,如果有效,您會想要得到清理過的標準格式。 在一個新的類中包裹這對於一個方法來說感覺很重,而輸出參數在某種方式上會讓輸入與輸出混雜在一起而變得不易維護。 元組被新增到語言中,以便這種確切情況能有一個更清晰的答案。

在他的影片《Intro to Tuples in C# In 10 Minutes or Less》中,Tim Corey 通過構建一個需要返回格式化字串和有效性標誌的小型地址驗證方法來演示元組。 在此過程中,他涵蓋了返回元組的語法、命名成員的重要性、如何在調用點將結果分解成獨立變數,以及如何使用丟棄字元跳過不需要的部分。 還在使用隨手的結果類或者 out 參數的讀者會在這裡找到一個更輕量的樣式。

問題:返回超過一個值

[0:18 - 2:50] Tim 以一個接收街道地址字串的 ValidateAddress 方法開場。 他所期望的行為很簡單:如果輸入符合"123 Sesame St",則返回正確格式化的"123 Sesame Street"; 否則,表示地址無效。 需要從一個調用中返回兩條資訊:清理過的字串和成功標誌。

在元組之前的選項都很尷尬。 建立一個 ValidateAddressResult 類可以做到,但它留下一個無人會實例化的用途單一的型別在項目中。 使用輸出參數在參數列表中返回格式化地址也可行,但這樣會把輸入輸出混合在方法簽名中並使調用點更難閱讀。 引入元組來處理此情況,不需要付出這兩種代價。

返回未命名元組

[2:50 - 4:01] 元組返回型別的最小語法是用括號包裹兩個型別:

public (string, bool) ValidateAddress(string address)
{
    if (address == "123 Sesame St")
    {
        return ("123 Sesame Street", true);
    }
    return (address, false);
}
public (string, bool) ValidateAddress(string address)
{
    if (address == "123 Sesame St")
    {
        return ("123 Sesame Street", true);
    }
    return (address, false);
}

該方法現在返回一個 (string, bool) 對。 當某物嘗試使用它時不利之處立即顯露出來。 由於成員沒有分配名稱,IntelliSense 將其顯示為 Item1Item2,這對下一位讀者來說完全不知道每個值代表什麼。 Tim 認為這是他從不使用未命名的元組的原因,即使語法是最短的。六個月後讀取 result.Item2 的成本比一次命名的成本更高。

命名元組成員

[4:01 - 6:30] 為每個元組成員分配名稱只是對返回型別聲明的單行更改:

public (string Address, bool IsValid) ValidateAddress(string address)
{
    if (address == "123 Sesame St")
    {
        return ("123 Sesame Street", true);
    }
    return (address, false);
}
public (string Address, bool IsValid) ValidateAddress(string address)
{
    if (address == "123 Sesame St")
    {
        return ("123 Sesame Street", true);
    }
    return (address, false);
}

現在調用點很自然地閱讀:

var result = ValidateAddress("123 Sesame St");

if (result.IsValid)
{
    Console.WriteLine($"Your validated address is {result.Address}");
}
else
{
    Console.WriteLine("That is an invalid address");
}
var result = ValidateAddress("123 Sesame St");

if (result.IsValid)
{
    Console.WriteLine($"Your validated address is {result.Address}");
}
else
{
    Console.WriteLine("That is an invalid address");
}

運行具有"123 Sesame St"的程式碼會列印出標準格式。 去掉開頭的 1 以生成"23 Sesame St"使 IsValid 返回 false 並列印出無效地址資訊。 該方法的契約現在在調用點是自我記錄的,不需要一個命名元組支持的類文件。

元組可以包含多於兩個成員。 三、四或五個元組使用相同的方式。 Tim 指出,一旦元組超過三或四個成員,記錄或類通常成為更清晰的選擇,但對於單個方法的兩或三個相關值,元組仍然是較輕的選擇。

將元組解構為獨立變數

[6:30 - 7:39] 有時候調用者更希望將結果的每個部分保存在自己的變數中,而不是點入單一的 result。 C# 直接支持這種解構語法:

(string message, bool valid) = ValidateAddress("123 Sesame St");

if (valid)
{
    Console.WriteLine($"Your validated address is {message}");
}
(string message, bool valid) = ValidateAddress("123 Sesame St");

if (valid)
{
    Console.WriteLine($"Your validated address is {message}");
}

左側的變數名稱不必與方法中的元組成員名稱匹配。 這裡 message 替換了 Address,而 valid 替換了 IsValid。 Tim 指出這是一個 解構器,而不是一個解構函式; 這兩個詞聽起來相似,但指的是完全不同的概念。解構器將元組拆分為調用者實際想要的本地變數。

用丟棄字元跳過值

[7:41 - 8:54] 當調用者只關心返回值的子集時,丟棄字元 (_) 可以去掉他們不需要的:

(string message, _) = ValidateAddress("123 Sesame St");
Console.WriteLine(message);
(string message, _) = ValidateAddress("123 Sesame St");
Console.WriteLine(message);

下劃線告訴編譯器"我故意忽略此值"。這比將不需要的成員分配給像 unused 之類的垃圾變數名更具表達性,因為丟棄表達了意圖。 任何人在閱讀行時都知道忽略 IsValid 是對此調用點的故意選擇,而不是疏忽。

總結:當元組值得存在

[8:54 - 9:28] 元組的主要用途是在不建立僅為返回而存在的類別的情況下從方法返回多個值。 在方法簽名處命名成員、在調用點解構它們,以及丟棄調用者不需要的那些是讓元組容易接受的三種模式。 除此之外,元組在LINQ 投影和中間計算中很有用,在那裡快速配對值比匿名型別更易於閱讀。

結論

[9:28 - 9:49] 元組為 C# 提供了一種緊湊的方法來從方法返回多個值。 命名形式是日常使用中值得使用的形式,因為 result.Address 閱讀起來很順,而 result.Item1 不順。 在呼叫者偏好此結構時,解構可以將部件恢復成本地變數,而丟棄字元允許一次調用只取需要的部分。

範例提示:當您開始在三個或更多地方解構相同的元組形狀時,這是信號,意味著要升級到記錄。 當形狀限於一個方法的時候,元組大放光彩; 一旦該形狀成為您的領域的一部分,命名型別就會物有所值。

在他的 YouTube 頻道上觀看完整的影片,在 10 分鐘培訓系列中獲得更多關於撰寫現代、富表達力 C# 的見解。

Hero Worlddot related to C#中元組的簡介,十分鐘內了解
Hero Affiliate related to C#中元組的簡介,十分鐘內了解

分享您所愛以賺取更多報酬

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

Iron 支援團隊

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