[C#7] 1.Tuples(元组)

简介: 1. 老版本代码 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 var fullName = GetFullName(); 6 7 Console.

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来引入到你当前的项目中(https://www.nuget.org/packages/System.ValueTuple/)。

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)这种新语法形式均可以)。

参考:

https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

https://docs.microsoft.com/en-us/dotnet/articles/csharp/tuples

 

作者: Blackheart
目录
相关文章
|
8月前
|
C# 开发者
C# 7.0 中的元组:多值返回与结构化数据的便捷之道
【1月更文挑战第7天】C# 7.0 引入了元组作为一等公民,为开发者提供了一种方便的方式来返回多个值和处理结构化数据。元组不仅使方法能够返回多个不同类型的值,还通过语义化的命名提高了代码的可读性和可维护性。本文将探讨C# 7.0中元组的概念、特性、用法以及它们如何提升编程效率和代码质量。
|
5月前
|
存储 C#
C#语言进阶(三) 元组
C#语言进阶(三) 元组
40 0
|
C# 网络架构 数据库
C#语法——元组类型
元组Tuple     我们现在使用的C#语法已经可以满足日常的开发需求,但C#语法还在进行版本的更新,在创造更多更优秀的语义来让我们使用。这里介绍一下C#5.0里的提供的语法——元组。   在C#中定义Tuple对象,转到定义查看,我们会看到如下代码 #region 程序集 mscorlib, Version=4.
1350 0
|
8月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
225 3
|
2月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
44 3
|
17天前
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
65 12
|
2月前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
74 4
|
4月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
56 2