選擇適當的類型牽涉到考慮其可用性、效能和取捨與其他類型相比。 自 C# 3.0 以來,已有匿名型別可供使用,而泛型 System.Tuple<T1,T2> 型別則以 .NET Framework 4.0 引進。 自那時以來,語言層級支持引進了新的選項,例如 System.ValueTuple<T1,T2> ,其名稱表示,提供具匿名型別彈性的實值型別。 在本文中,您將瞭解何時適合選擇其中一種類型而不是另一種類型。
可用性和功能
C# 3.0 中引進了匿名型別,其中包含 Language-Integrated Query (LINQ) 表達式。 使用 LINQ 時,開發人員通常會將查詢的結果投影為匿名類型,這些類型會保存他們正在使用的物件中一些選取的屬性。 請考慮以下範例,实例化一個 DateTime 物件的陣列,並迭代這些物件以投射到具有兩個屬性的匿名型別中。
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var anonymous in
dates.Select(
date => new { Formatted = $"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks }))
{
Console.WriteLine($"Ticks: {anonymous.Ticks}, formatted: {anonymous.Formatted}");
}
匿名型別會使用 new
運算符來具現化,而且屬性名稱和類型是從宣告推斷而來。 如果相同元件中的兩個或多個匿名物件初始化表達式指定相同順序且具有相同名稱和類型的屬性序列,編譯程式會將物件視為相同類型的實例。 這些物件會共用編譯器產生的相同類型資訊。
先前的 C# 代碼段會投影具有兩個屬性的匿名類型,這與下列編譯程式產生的 C# 類別類似:
internal sealed class f__AnonymousType0
{
public string Formatted { get; }
public long Ticks { get; }
public f__AnonymousType0(string formatted, long ticks)
{
Formatted = formatted;
Ticks = ticks;
}
}
如需詳細資訊,請參閱 匿名類型。 在投影至 LINQ 查詢時,元組具有相同的功能,您可以選擇屬性轉換為元組。 這些 Tuple 會流經查詢,就像匿名類型一樣。 現在,請考慮以下使用 System.Tuple<string, long>
的範例。
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var tuple in
dates.Select(
date => new Tuple<string, long>($"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {tuple.Item2}, formatted: {tuple.Item1}");
}
System.Tuple<T1,T2>使用 時,實體會公開編號的項目屬性,例如Item1
、 和 Item2
。 這些屬性名稱可讓您更難以瞭解屬性值的意圖,因為屬性名稱只提供序數。 此外,這些 System.Tuple
類型是參考型別 class
。 不過,System.ValueTuple<T1,T2>是值類型struct
。 下列 C# 代碼段會使用 ValueTuple<string, long>
進行投影。 如此一來,它會使用字面語法來指定。
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var (formatted, ticks) in
dates.Select(
date => (Formatted: $"{date:MMM dd, yyyy at hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {ticks}, formatted: {formatted}");
}
如需 Tuple 的詳細資訊,請參閱 Tuple 類型 (C# 參考) 或 Tuple (Visual Basic) 。
上述範例在功能上都是相等的,不過,其可用性和基礎實作稍有差異。
取捨
您可能會想總是使用 ValueTuple 而不是 Tuple,並考慮匿名類型,但其中有一些利弊需要您仔細考量。 ValueTuple 類型是可變的,而 Tuple 類型是唯讀的。 匿名型別可用於表達式樹中,而元組則不能。 下表概述一些主要差異。
主要差異
名稱 | 存取修飾詞 | 類型 | 自訂成員名稱 | 解構支援 | 表達式樹支援 |
---|---|---|---|---|---|
匿名型別 | internal |
class |
✔️ | ❌ | ✔️ |
Tuple | public |
class |
❌ | ❌ | ✔️ |
ValueTuple | public |
struct |
✔️ | ✔️ | ❌ |
序列化
選擇類型時,有一個重要考慮是是否需要串行化。 序列化是將物件狀態轉換為可保存或傳輸的形式的過程。 如需詳細資訊,請參閱 串行化。 當序列化很重要時,建立 class
或 struct
會優於匿名型別或 tuple型別。
績效
這些類型的效能取決於案例。 主要影響涉及配置與複製之間的取捨。 在大部分情況下,影響很小。 當可能發生重大影響時,應該採取測量來通知決策。
結論
身為開發人員,在選擇使用 Tuple 和匿名類型時,需要考慮多個因素。 一般而言,如果您不使用 表達式樹狀結構,且熟悉元組語法,那麼可以選擇 ValueTuple,因為它們提供具名稱屬性彈性的值型別。 如果您正在使用表達式樹狀架構,而且想要命名屬性,請選擇匿名類型。 否則,請使用 Tuple。