1. 老版本代码
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<T>来处理这个题目,这个范例位于一个零丁的dll(System.ValueTuple)中,能够经由过程nuget来引入到你当前的项目中(http://www.ki4.cn/)。
2. 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中。
3. Example
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. 总结
新的语法情势确切直观友爱了很多,but,实质依然是借助泛型范例来完成的,同时也须要编译器对新语法情势的支撑。
了解了实质是什么东西今后,今后在项目中环境许可的话,就放心大胆的运用吧(范例ValueTuple能够涌现的处所,(first,last)这类新语法情势均能够)。
以上就是C#Tuples(元组)的细致内容,更多请关注ki4网别的相干文章!