Tuple(元組)源自函數式程式設計,早見於 Erlang、F# 等語言。.NET 4.0 將其納入基礎類別庫(BCL),作為 C# 邁向函數式風格的重要補充。本文深入剖析 Tuple 的結構、用法、內部實現與優缺點。
Tuple 表示有序、固定大小且異質的資料集合。在 .NET 中實現為泛型類別,n-Tuple 即包含 n 個元素。例如表示日期的 3-Tuple:
var date = Tuple.Create<int, int, int>(2009, 5, 29);
// 類型為 Tuple<int, int, int>
透過 Tuple.Create 靜態工廠方法可自動推斷類型參數,簡化宣告。
.NET 4.0 預定義了 8 個 Tuple 泛型類別,從 1 到 8 個型別參數:
public class Tuple<T1> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
public class Tuple<T1, T2> : ...
...
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> : ...
所有類別皆實作 ITuple 介面(內部介面,外部不可直接存取),定義如下:
internal interface ITuple
{
int Size { get; }
int GetHashCode(IEqualityComparer comparer);
string ToString(StringBuilder sb);
}
Size 唯讀屬性回傳元素個數,ToString 用於格式化輸出。
Tuple 適合作為「臨時資料結構」,避免為一次性資料建立專屬類別:
public class MyRequest
{
public Tuple<string, Uri, DateTime> GetMyRequest()
{
return Tuple.Create("anytao.com", new Uri("https://anytao.net/"), DateTime.Now);
}
}
常見應用場景:
Point {X, Y}Date {Year, Month, Day}、時間 Time {Hour, Minute, Second}DateTime {Date, Time}Request {Name, URL, Result}以 Tuple<T1, T2> 為例(經反編譯簡化):
[Serializable]
public class Tuple<T1, T2> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
{
private T1 m_Item1;
private T2 m_Item2;
public Tuple(T1 item1, T2 item2) { ... }
public T1 Item1 { get { return m_Item1; } }
public T2 Item2 { get { return m_Item2; } }
// ITuple 顯式實作
string ITuple.ToString(StringBuilder sb) { ... }
int ITuple.Size { get { return 2; } }
}
元素透過 Item1、Item2 ... ItemN 唯讀屬性存取,不支援迭代器(foreach),且 Size 為顯式介面實作,需轉型為 ITuple 才能存取(但介面為 internal,外部無法直接使用)。
當元素超過 7 個時,必須使用 8 參數版本,且第 8 參數 TRest 必須是另一個 Tuple,否則拋出 ArgumentException:
// 錯誤:第 8 參數不是 Tuple
var t8 = Tuple.Create(1, 2, 3, 4, 5, 6, 7, 8); // 拋出異常
// 正確:第 8 參數為 Tuple<int>
var trest = Tuple.Create(8);
var t8 = Tuple.Create(1, 2, 3, 4, 5, 6, 7, trest);
Console.WriteLine(t8.Rest); // 輸出 (8)
這是因為建構函式強制檢查 rest is ITuple。設計上雖允許無限擴展,但語法顯得笨重。
| 優勢 | 不足 |
|---|---|
| 方法多返回值的優雅方案 | 成員數量固定(最多 8 個),缺乏動態性 |
| 靈活構建臨時資料結構,免去定義類別 | 第 8 參數強制為 Tuple,擴展語法繁瑣 |
| 強類型、編譯期檢查 | 無法直接 foreach 遍歷,Size 需介面轉型 |
| 實作結構比較(IStructuralEquatable/Comparable) | ITuple 為 internal,無法自行擴展繼承體系 |
Tuple 為 C# 帶來了函數式風味的資料攜帶方式,極大簡化了臨時資料結構的定義。雖然有固定元數與擴展不便的限制,但在「隨用隨取」的輕量級場景下,它是不可或缺的利器。後續版本(C# 7+)引入的 ValueTuple 結構體與語法糖(如 (int, string))則進一步解決了效能與語法痛點,值得持續關注。