元組 (ValueTuple)類型是值類型;元組元素是公共字段,可以使用任意數量的元素定義元組。Tuple類型像一個口袋,在出門前可以把所需的任何東西一股腦地放在里面。您可以將鑰匙、駕駛證、便箋簿和鋼筆放在口袋里,您的口袋是存放各種東西的收集箱。
到了c# 4.0 應當使用元組Tuple而不是使用輸出參數,在任何時候都應避免使用ref/out傳遞參數,尤其對引用類型。
繼承
Object-> ValueType ->Enum
Object-> ValueType ->struct 包括int float等簡單值類型 Object-> ValueType ->ValueTuple Object-> ValueType ->Nullable
元組項命名准則
務必對使用元組語法聲明的所有變量使用駝峰式大小寫。
****考慮對所有元組項名稱使用 Pascal 命名法。
為什么要使用元組?
有時,可能會發現,將數據元素組合在一起非常有用。例如,假設要處理國家/地區相關信息,如 2017 年世界上最貧窮的國家/地區馬拉維。它的首都是利隆圭,人均國內生產總值 (GDP) 為 226.50 美元。顯然,可以為此類數據聲明一個類,但它並不是真正典型的名詞/對象。它似乎更像是一組相關數據,而不是對象。當然,若要設置 Country 對象(舉個例子),所含數據遠不止 Name、Capital 和 GDP per capita 這些屬性。也可以將每個數據元素存儲在各個變量中,但這樣做的結果是,數據元素相互沒有任何關聯。除了變量名稱可能共用后綴或前綴之外,226.50 美元與馬拉維將無任何關聯。另一種方法是,將所有數據組合到一個字符串中。不過,這樣做的缺點是,必須先分析各個數據元素,然后才能分別處理這些元素。最后一種方法是創建匿名類型,但這樣做同樣有局限性。其實,元組足以完全替代匿名類型.-----Mark Michaelis
一、元組聲明和分配示例代碼:
//元組寫法1通過example2.Item來引用 var example1 = (1,2,3,4,5,"23",1,2,3,1,5,6,2,3); Console.WriteLine(example1.Item10); //元組寫法2, 通過example3.變量名引用 var example2 = (exa1:1, exa2: 2,3,4,5,6); Console.WriteLine(example2.exa2); //元組寫法3, 通過example3.變量名引用 左側不允許棄元 (int age, string name) example3 = (3, "Dog3"); Console.WriteLine(example3.name); //元組寫法4 相當於批量賦值 可以單獨使用 變量 左側不允許棄元 (string sr, bool sb, int sc) = ("4sr",true,1); Console.WriteLine(sr); //元組寫法5 元組元素是公共字段 所以可以單獨引用 var (exa51, exa52) = ("51f", 5.1); Console.WriteLine(exa51); //元組寫法6 元組元素是公共字段 所以可以單獨引用 var example6 = ("post office", 6.3); (string destination, double distance) = example6; Console.WriteLine(distance); //元組寫法7 將元組分配到各個已預聲明的變量中。 var exa71 = string.Empty; var exa72 = 0.0; var example7 = ("post office", 7.2); (exa71, exa72) = example7; Console.WriteLine(exa72); //元組寫法8 將元組分配到各個已預聲明的變量中。 string country; string capital; double gdpPerCapita; (country, capital, gdpPerCapita) =("Malawi", "Lilongwe", 226.50); System.Console.WriteLine( $"The poorest country in the world in 2017 was {country}, {capital}: {gdpPerCapita}"); //元組寫法9 棄元 將未命名的元組分配到一個隱式類型化變量中, var countrInfo = ("Malawi", "Lilongwe", 226.50); (string name, _, double gdpPerCapit) = countrInfo; Console.WriteLine(gdpPerCapit); //C#10混合定義 int y = 0; (var x, y, var z) = (1, 2, 3); 部分內容來源:https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2017/august/essential-net-csharp-7-0-tuples-explained
二、元組賦值和析構
C# 支持滿足以下兩個條件的元組類型之間的賦值:
1、兩個元組類型有相同數量的元素
2、對於每個元組位置, 右側元組元素的類型與左側相應的元組元素的類型相同或可以隱式轉換為左側相應的元
組元素的類型
(int, double) t1 = (17, 3.14); (double First, double Second) t2 = (0.0, 1.0); t2 = t1; Console.WriteLine(t2);
三、比較運算符!= 和== 從 C# 7.3 開始支持
元組賦值和元組相等比較不會考慮字段名稱。
同時滿足以下兩個條件時,兩個元組可比較:
兩個元組具有相同數量的元素。 例如,如果 t1 和 t2 具有不同數目的元素, t1 != t2 則不會進行編譯。
對於每個元組位置,可以使用 == 和 != 運算符對左右側元組操作數中的相應元素進行比較。 例如,
(1, (2, 3)) == ((1, 2), 3) 不會進行編譯,因為 1 不可與 (1, 2) 比較。
(int a, byte b) left = (5, 10); (long a, int b) right = (5, 10); Console.WriteLine(left == right); // output: True Console.WriteLine(left != right); // output: False var t1 = (A: 5, B: 10); var t2 = (B: 5, A: 10); Console.WriteLine(t1 == t2); // output: True Console.WriteLine(t1 != t2); // output: False
== 和 != 運算符將以短路方式對元組進行比較。 也就是說,一旦遇見一對不相等的元素或達到元組的末尾,操
作將立即停止。 但是,在進行任何比較之前,將對所有元組元素進行計算,如以下示例所示:
Console.WriteLine((Display(1), Display(2)) == (Display(3), Display(4))); int Display(int s) { Console.WriteLine(s); return s; } // Output: // 1 // 2 // 3 // 4 // False
四、元組作為 out 參數
通常,你會將具有 out 參數的方法重構為返回元組的方法。 但是,在某些情況下, out 參數可以是元組類型。
下面的示例演示了如何將元組作為 out 參數使用:
var limitsLookup = new Dictionary<int, (int Min, int Max)>() { [2] = (4, 10), [4] = (10, 20), [6] = (0, 23) }; if (limitsLookup.TryGetValue(4, out (int Min, int Max) limits)) { Console.WriteLine($"Found limits: min is {limits.Min}, max is {limits.Max}"); } // Output: // Found limits: min is 10, max is 20
五、元組與 System.Tuple
System.ValueTuple 類型支持的 C# 元組不同於 System.Tuple 類型表示的元組。 主要區別如下:
ValueTuple 類型是值類型。 Tuple 類型是引用類型。
ValueTuple 類型是可變的。 Tuple 類型是不可變的。
ValueTuple 類型的數據成員是字段。 Tuple 類型的數據成員是屬性。
六、元組結構
//元組寫法9 棄元 將未命名的元組分配到一個隱式類型化變量中, var countrInfo = ("Malawi", "Lilongwe", 226.50); (string name, _, double gdpPerCapit) = countrInfo;
上面代碼是不是很驚奇,反正我第一次看到時特別驚訝,也感覺特別有意思,那么這到底怎么實現的呢,我查看一下iL代碼:
原來只是在類中添加一個解構函數(Deconstruct)就可以,解構參數方法名稱必須是Deconstruct,返回值必須是void,參數列表必須是out
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);