1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var fullName = GetFullName(); 6 7 Console.WriteLine(fullName.Item1);// Item1,2,3不能忍,,, 8 Console.WriteLine(fullName.Item2); 9 Console.WriteLine(fullName.Item3);10 }11 static Tuple<string, string, string> GetFullName() => new Tuple<string, string, string>("first name", "blackheart", "last name");12 }
在某些場景下,我們需要一個方法傳回一個以上的回傳值,微軟在.NET 4中引入了Tuple這個泛型類,可以允許我們回傳多個參數,每個參數都依照順序命名為 Item1;Item2,Item3 ,算是部分的解決了我們的問題,但是對於強迫症程式設計師來說, Item1,2,3的命名簡直是不能忍受的,,,so,在C#7中,引入了一個新的泛型型別ValueTuple
不要廢話,直接看程式碼:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var fullName = GetFullName(); 6 7 Console.WriteLine(fullName.First); // 终于可以不是Item1,2,3了,,, 8 Console.WriteLine(fullName.Middle); 9 Console.WriteLine(fullName.Last);10 }11 12 static (string First, string Middle, string Last) GetFullName() => ("first name", "blackheart", "last name");13 }
看出來差別了嗎?我們終於可以用更直覺的名字來替換掉該死的"Item1,2,3"了,看起來很棒吧。但似乎我們並沒有用到上面我提到的System.ValueTuple,我們翻開編譯後的組件看看:
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 ValueTuple<string, string, string> fullName = Program.GetFullName(); 6 Console.WriteLine(fullName.Item1); // 原来你还是Item1,2,3,,,FUCK!!! 7 Console.WriteLine(fullName.Item2); 8 Console.WriteLine(fullName.Item3); 9 }10 11 [TupleElementNames(new string[]12 {13 "First",14 "Middle",15 "Last"16 })]17 private static ValueTuple<string, string, string> GetFullName()18 {19 return new ValueTuple<string, string, string>("first name", "blackheart", "last name");20 }21 }
不不知道,一看嚇一跳,原來我們的fullName.First; 編譯後居然還是fullName.Item1 ,真是日了狗了。 。 。
不同之處在於GetFullName這個方法,編譯器把我們簡化的語法形式翻譯成了 ValueTuple<string, string, string> ,也給加了一個新的Attribute(TupleElementNamesAttribute),然後把我們自定義的非常直觀友好的“First”,"Middle","Last "當作元資料給存起來了(如果只是局部使用,則不會加入這樣的元資料)。 TupleElementNamesAttribute和ValueTuple一樣,位於System.ValueTuple的單獨dll中。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var range = (first: 1, end: 10); 6 //也可以这样写,效果是一样的,编译后都是没有了first,end的痕迹,,,first和end只是语法层面的障眼法 7 //(int first, int last) range = (1, 10); 8 Console.WriteLine(range.first); 9 Console.WriteLine(range.end);10 11 //可以使用var,这种无显示声明一个变量的方式会编译出多余的代码,慎用,不知是不是还未优化好。12 (var begin, var end) = (DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31"));13 Console.WriteLine(begin);14 Console.WriteLine(end);15 16 //begin,end可以被覆盖重命名为startDate和endDate,但是会有一个编译警告,提示名字被忽略掉了。17 //warning CS8123: The tuple element name 'begin' is ignored because a different name is specified by the target type '(DateTime startDate, DateTime endDate)'18 //warning CS8123: The tuple element name 'end' is ignored because a different name is specified by the target type '(DateTime startDate, DateTime endDate)‘19 (DateTime startDate, DateTime endDate) timeSpan = (begin: DateTime.Parse("2017-1-1"), end: DateTime.Parse("2017-12-31"));20 Console.WriteLine(timeSpan.startDate);21 Console.WriteLine(timeSpan.endDate);22 }23 }
look一下編譯後的程式碼:
##
1 private static void Main(string[] args) 2 { 3 ValueTuple<int, int> range = new ValueTuple<int, int>(1, 10); 4 Console.WriteLine(range.Item1); 5 Console.WriteLine(range.Item2); 6 ValueTuple<DateTime, DateTime> expr_3C = new ValueTuple<DateTime, DateTime>(DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31")); 7 DateTime item = expr_3C.Item1; 8 DateTime item2 = expr_3C.Item2; 9 DateTime begin = item; 10 DateTime end = item2;11 Console.WriteLine(begin);12 Console.WriteLine(end);13 ValueTuple<DateTime, DateTime> timeSpan = new ValueTuple<DateTime, DateTime>(DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31"));14 Console.WriteLine(timeSpan.Item1);15 Console.WriteLine(timeSpan.Item2);16 }
(var begin, var end) = (DateTime.Parse("2017-1- 1"), DateTime.Parse("#2017-12-31")); 這一行的便宜結果,看起來很糟糕(上述6-10行紅色部分),可能還是編譯最佳化不足的問題吧(release編譯也是如此)。
4.類型ValueTuple可以出現的地方,(first,last)這種新語法形式均可)。
以上是C#Tuples(元組)的詳細內容。更多資訊請關注PHP中文網其他相關文章!