CodeGym /課程 /C# SELF /元素命名與 tuple 解構

元素命名與 tuple 解構

C# SELF
等級 11, 課堂 2
開放

1. Tuple 命名:為解構提供語境

在上一堂課我們已經認識過 tuple 的命名元素,這讓你的程式碼更好懂,不用再用沒意義的 Item1、Item2,而是用有意義的名字(像是 person.Name)。給 tuple 元素命名特別重要,當它們被用來當作方法、參數或屬性的回傳值時。命名就是讓解構更方便的關鍵前提,這點我們等等會深入聊。

提醒一下,名字可以在 tuple 初始化時用 literal 指定,也可以在方法、屬性或欄位的回傳型別簽名裡指定。

方法範例: 方法回傳值裡的 tuple 命名元素


public static (int 年齡, string 名字) GetPetInfo()
{
    return (年齡: 5, 名字: "巴爾西克");
}

// 使用方式:
var info = GetPetInfo();
Console.WriteLine($"{info.名字} — {info.年齡} 歲");

欄位/屬性範例: 欄位/屬性裡的 tuple 命名元素


public (int 寬度, int 高度) ImageSize = (1024, 768);

記得: 如果沒明確指定名字,元素還是可以用 Item1、Item2 這種方式取用。這會讓程式碼比較難懂,尤其 tuple 用到後面時。所以建議只要語意不明顯,就一定要給元素取個有意義的名字。

2. Tuple 解構

什麼是解構?

解構就是把 tuple「拆開」成多個變數,這樣用起來更方便。比如說,從 (年齡: 5, 名字: "巴爾西克") 這個 tuple,可以直接拿到兩個變數:年齡 和 名字。

比喻: 想像 tuple 就像一個有標籤的盒子,解構就是你把盒子裡的東西直接攤開放桌上。

解構語法


var pet = (年齡: 5, 名字: "巴爾西克");
var (age, name) = pet;
Console.WriteLine($"{name} — {age} 歲");
Tuple 解構到變數

現在我們有兩個變數:age 和 name。它們拿到 tuple 裡的值。左邊的名字(age、name)不用跟 tuple 裡的名字一樣,這只是新的區域變數而已。

解構函式回傳值

很多時候 tuple 都是用來回傳多個值,這時解構就超方便:


public static (double 最小值, double 最大值) GetMinMax(int[] 資料)
{
    int 最小值 = 資料.Min();
    int 最大值 = 資料.Max();
    return (最小值, 最大值);
}

var 數字們 = new[] { 1, 2, 3, 4, 5 };
var (minValue, maxValue) = GetMinMax(數字們);
Console.WriteLine($"最小值: {minValue}, 最大值: {maxValue}");
解構函式回傳值

注意,解構時變數名稱可以根據當下語境自己取。

用 var 解構

var (a, b) = (10, 20); // int a = 10, b = 20

解構和 discard _

有時候 tuple 裡不是每個元素都需要,可以用 _(discard)來忽略。 Discard(_)就是告訴編譯器「我知道這裡有個元素,但我不需要,不要幫我創變數」。

這樣你解構 tuple 時,可以在不需要的地方留個「洞」。超簡潔又不會亂丟沒用的變數!


var pet = (年齡: 5, 名字: "巴爾西克", 開心嗎: true);
var (age, _, isHappy) = pet; // 只要 age 和 isHappy,名字直接忽略
用 discard _ 解構

有趣的是:discard 很常用來避免 namespace 裡出現一堆沒用的變數。

在 foreach 裡解構

C# 可以直接在 foreach 裡解構 tuple 陣列:


var pets = new (string 名字, int 年齡)[]
{
    ("巴爾西克", 5),
    ("穆西亞", 3),
    ("約翰尼", 7)
};

foreach (var (name, age) in pets)
{
    Console.WriteLine($"{name} — {age} 歲");
}
在 foreach 裡解構 tuple

3. 元素命名和型別的運作方式

命名元素的行為

Tuple 元素的名字只是「語法糖」,也就是寫給人看的。編譯時名字會變成內部欄位 Item1、Item2 等等,但 IDE 和編譯器會保留名字讓你用。

對型別相容性和轉型的影響

兩個 tuple 只要元素數量和型別一樣,不管名字怎麼取,對編譯器來說都是同一種型別。元素名字不會影響型別判斷:


var t1 = (X: 42, Y: 13);
var t2 = (A: 42, B: 13);
t1 = t2; // OK
Console.WriteLine(t1.X); // 42
不同元素名字的 tuple 也能相容

但在寫表達式和 IntelliSense 提示時,會用左邊(被賦值那邊)的名字,不會用右邊的。

隱式和顯式命名

這之前有提過,再提醒一次:tuple 可以只給部分元素命名,也可以完全不命名——那就會是 Item1 這種預設名字。


var point = (X: 10, 20); // X 和 Item2
Console.WriteLine(point.X);     // 10
Console.WriteLine(point.Item2); // 20
部分命名的 tuple

建議: 只要 tuple 有超過一兩個元素,或是值的意義不明顯,就一定要幫元素命名。

4. 使用命名和解構時的常見錯誤與細節

錯誤一:「名字搬家」問題
如果你先宣告了一個有名字的 tuple,然後賦值給另一個沒有名字(或名字不同)的 tuple,IntelliSense 還是會顯示原本的名字。像這樣:


var original = (X: 1, Y: 2);
var alias = original;            // alias.X == 1, alias.Y == 2

original = (10, 20);             // 沒有名字的 tuple
Console.WriteLine(alias.X);      // 還是可以用,alias 還是保留舊名字

錯誤二:元素名字重複
不能給兩個元素同樣的名字——編譯器會報「Duplicate tuple element name」錯誤:


var badTuple = (A: 1, A: 2);     // 錯誤 CS8122: Duplicate tuple element name 'A'

錯誤三:解構元素數量不符
解構時變數數量一定要跟 tuple 元素數量一樣,不然會報錯:


var pet = (年齡: 5, 名字: "巴爾西克");
var (age, name, mood) = pet;     // 錯誤 CS8124: Tuple must contain exactly 3 elements

錯誤四:錯誤使用 discard _
用 _ 忽略元素時,每個位置都要單獨寫,不能「合併」跳過多個。像這樣會錯:


var data = (1, 2, 3);
var (_, x, _) = data;            // 正確:跳過第一和第三個元素
var (_, _) = data;               // 錯誤 CS8124: Tuple must contain exactly 2 elements

2
任務
C# SELF, 等級 11, 課堂 2
上鎖
建立具名 Tuple 並輸出元素
建立具名 Tuple 並輸出元素
2
任務
C# SELF, 等級 11, 課堂 2
上鎖
解構方法返回值
解構方法返回值
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION