anytao.net | 《你必须知道的.NET》网站 | Anytao技术博客 

发布日期:2009.06.01 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。

Tuple,是函数式编程的概念之一,早见于Elang、F#等动态语言。不过,我第一次听说Tuple还早在2005年园子的Ninputer大牛提出在.NET 2.0实现Tuple的基本想法,我们可以通过以下地址仰慕当时的历史片段:
探讨.NET 2.0中Tuple的实现方法
由此可见,Tuple不是.NET 4.0的创造发明,但却是C#趋于函数式编程概念的必要补充。那么,我们首先来看看,什么是Tuple?

Tuple为何物?

什么是Tuple,在汉语上我们将其翻译为元组。Tuple的概念源于数学概念,表示有序的数据集合。在.NET中Tuple被实现为泛型类型,n-Tuple表示有n个元素的Tuple,集合的元素可以是任何类型,例如定义一个3-Tuple表示Date(Year, Month, Day)时可以定义为:

// Release : code01, 2009/05/29
// Author  : Anytao, http://www.anytao.com
var date = Tuple.Create<int, int, int>(2009, 5, 29);

通过Tuple.Create<int, int, int>将定义一个Tuple<int, int, int>实例,该实例实现三个数据成员:

对于Tuple的具体解析我们随后分析,当下仅了解一个大致。

我们可以有两个方面的理解,在.NET中关于Tuple我们有如下的定义:

  • 广义上, Tuple就是一种数据结构,通常情况下,其成员的类型及数据是确定的。
  • 狭义上,凡是实现了ITuple接口的类型,都是Tuple的实例。在.NET 4.0 BCL中,预定义了8个Tuple类型。例如最简单的Tuple定义为:
public class Tuple<T1> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
{
}

其他所有的Tuple类型都实现了ITuple接口,该接口被定义为:

interface ITuple
{int Size { get; }int GetHashCode(IEqualityComparer comparer);string ToString(StringBuilder sb);
}

在该接口中,定义了一个只读属性Size、两个覆写方法GetHashCode和ToString,实现该接口的Tuple八大金刚如下:

public class Tuple<T1>
public class Tuple<T1, T2>
public class Tuple<T1, T2, T3>
public class Tuple<T1, T2, T3, T4>
public class Tuple<T1, T2, T3, T4, T5>
public class Tuple<T1, T2, T3, T4, T5, T6>
public class Tuple<T1, T2, T3, T4, T5, T6, T7>
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

注:Size属性、ToString(StringBuilder sb)方法,均被实现为显示接口方法,所以只能以接口实例访问,不过ITuple本身被定义internal,意味着我们无法在程序中访问ITuple,何意何解尚不明确。

在下面的定义中,我们将Custom Request封装为Tuple:

// Release : code02, 2009/05/29
// Author  : Anytao, http://www.anytao.com
public class MyRequest
{public Tuple<string, Uri, DateTime> GetMyRequest(){return Tuple.Create<string, Uri, DateTime>("anytao.com", new Uri("http://anytao.net/"), DateTime.Now);}
}

为什么要用Tuple呢?这是个值得权衡的问题,上述MyRequest类型中通过3-Tuple对需要的Request信息进行封装,我们当然也可创建一个新的struct来封装,两种方式均可胜任。然则,在实际的编程实践中,很多时候我们需要一种灵活的创建一定数据结构的类型,很多时候新的数据结构充当着“临时”角色,通过大动干戈新类型完全没有必要,而Tuple既是为此种体验而设计的。例如:

  • Point {X, Y},可以表示坐标位置的数据结构。
  • Date {Year, Month, Day},可以表示日期结构;Time {Hour, Minute, Second},可以表示时间结构;而DateTime {Date, Time}则可以实现灵活的日期时间结构。
  • Request {Name, URL, Result},可以表示Request的若干信息。
  • 。。。,随需而取。

Tuple inside

为了对Tuple一探究竟,我们使用Reflector工具打开神秘之门,就实现而言,Tuple类型略显单薄,并没有什么“神奇”的设计,以Tuple<T1, T2>而言,我们可以看到其部分实现:

[Serializable]
public class Tuple<T1, T2> : IStructuralEquatable, IStructuralComparable, IComparable, ITuple
{// Fieldsprivate T1 m_Item1;private T2 m_Item2;// Methodspublic Tuple(T1 item1, T2 item2){this.m_Item1 = item1;this.m_Item2 = item2;}string ITuple.ToString(StringBuilder sb){sb.Append(this.m_Item1);sb.Append(", ");sb.Append(this.m_Item2);sb.Append(")");return sb.ToString();}int ITuple.Size{get{return 2;}}// Propertiespublic T1 Item1{get{return this.m_Item1;}}public T2 Item2{get{return this.m_Item2;}}//More and more...
}

其他的Tuple类型也大致如此,所以我们易于知晓Item1、Item2、…、ItemN是如何被定义的,同时也纳闷Size属性将何去何从,也打消了我们期望通过foreach来遍历Tuple元素的可能,未来如何,只有期待。

不过,对于Tuple而言,因为其元素数量的有限性,虽然能够满足大部分的需求,当时动态体验是我们越来越期望的编程体验。同时,尤其注意public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> 引发的可能ArgumentException,例如:

// Release : code03, 2009/05/31
// Author  : Anytao, http://www.anytao.com
var t8 = Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine(t8.Rest);

将引发异常:

Unhandled Exception: System.ArgumentException: The last element of an eight element tuple must be a Tuple.

提示我们最后的TRest应该为Tuple,所以修改程序为:

// Release : code04, 2009/05/31
// Author  : Anytao, http://www.anytao.com
var trest = Tuple.Create<int>(8);
var t8 = Tuple.Create<int, int, int, int, int, int, int, Tuple<int>>(1, 2, 3, 4, 5, 6, 7, trest);
Console.WriteLine(t8.Rest);

则没有任何问题,究其原因我们很容易从Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>构造方法中找到答案:

public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
{if (!(rest is ITuple)){throw new ArgumentException(Environment.GetResourceString("ArgumentException_TupleLastArgumentNotATuple"));}this.m_Item1 = item1;this.m_Item2 = item2;this.m_Item3 = item3;this.m_Item4 = item4;this.m_Item5 = item5;this.m_Item6 = item6;this.m_Item7 = item7;this.m_Rest = rest;
}

TRest类型参数必须被实现为ITuple,否则引发异常。TRest在某种程度上为元素的扩展带来点方便,但是我仔细想来,总觉此处TRest的设计有点多此一举,既然是类型参数,T1、T2、…、TN其实均可为ITuple实例,何必非拘泥于最后一个。

优略之间

当前,.NET 4.0预定义的Tuple类型仅有8个,所以我们应考虑对于Tuple提供适度扩展的可能, 然而遗憾的是ITuple类型被实现为internal,所以我们无法继承ITuple,只好自定义类似的实现:

优势所在:

  • 为方法实现多个返回值体验,这是显然的,Tuple元素都可以作为返回值。
  • 灵活的构建数据结构,符合随要随到的公仆精神。
  • 强类型。

不足总结:

  • 当前Tuple类型的成员被实现为确定值,目前而言,还没有动态决议成员数量的机制,如果你有可以告诉我:-)
  • public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>,可能引发ArgumentException。

参考文献

  • 探讨.NET 2.0中Tuple的实现方法
  • Tuple, a new type on .Net 4.0
  • Functional .NET 4.0 - Tuples and Zip
更多精彩,尽在anytao.net

anytao | © 2009 Anytao.com

2009/06/01 | http://anytao.cnblogs.com/ | http://anytao.net/blog/post/2009/05/31/anytao-insidenet-32-tupletalk.aspx

本文以“现状”提供且没有任何担保,同时也没有授予任何权利。 | This posting is provided "AS IS" with no warranties, and confers no rights.

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二相关推荐

  1. [你必须知道的.NET]第三十回:.NET十年(下)

    引言 语言是程序开发者行走江湖的手上利器,各大门派的高手在论坛.博客为了自家门派争吵不已早是技术世界中的亮丽风景,虽多少为刚刚踏入江湖的新手提供了思考的素材,但也同时迷惑了初出茅庐的前行方向. 本文不 ...

  2. [你必须知道的.NET]第三十五回,判断dll是debug还是release,这是个问题

    问题的提出 晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码方式来判断一个dll或者exe为debug build还是release build?由于没有太多的讨论,所以我只好自己找点儿办法,试图 ...

  3. [你必须知道的.NET]第三十四回,object成员,不见了!

    在.NET世界了,object是公认的造物主,其麾下的7大成员,个顶个的横行在任何系统的任何代码角落. public class Object {public Object();public virt ...

  4. [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

    总体来说,这是一篇介绍性的文章,不会涉及过多技术细节和研究过程.但是,作为拉开序幕的第一页,本文以提纲挈领的方式展开对.NET 4.0的初次体验.从What's new的角度,开始我对.NET 4.0 ...

  5. [你必须知道的.NET]第三十三回,深入.NET 4.0之,LazyT点滴

    对象的创建方式,始终代表了软件工业的生产力方向,代表了先进软件技术发展的方向,也代表了广大程序开发者的集体智慧.以new的方式创建,通过工厂方法,利用IoC容器,都以不同的方式实现了活生生实例成员的创 ...

  6. [你必须知道的.NET] 第三回:历史纠葛:特性和属性

    本文将介绍以下内容: • 定制特性的基本概念和用法 • 属性与特性的区别比较 • 反射的简单介绍 1. 引言 attribute是.NET框架引入的有一技术亮点,因此我们有必要花点时间来了解本文的内容 ...

  7. [导入][你必须知道的.NET] 第三回:历史纠葛:特性和属性

    摘要: 博客园中,关于attribute的讨论不是很多,所以本文也有了存在的意义.attribute是.NET框架引入的有一技术亮点,因此我们有必要花点时间来了解本文的内容,走进一个发现attribu ...

  8. 艾伟:[你必须知道的.NET] 开篇有益

    本系列文章导航 [你必须知道的.NET] 开篇有益 [你必须知道的.NET] 第一回:恩怨情仇:is和as [你必须知道的.NET] 第二回:对抽象编程:接口和抽象类 [你必须知道的.NET] 第三回 ...

  9. 整理下Anytao《你必须知道的.Net》全文链接

    不辞辛苦的一番抗吃赛抗吃喂o(∩_∩)o... [你必须知道的.NET] 第一回:恩怨情仇:is和as http://www.cnblogs.com/anytao/archive/2007/05/23 ...

最新文章

  1. Hibernate学习笔记(一)----针对不同的数据库不同的配置
  2. Ubuntu 16.04安装Java JDK
  3. MM 收货容差如何设定
  4. 一位软件实施工程师的自述
  5. 广义线性模型_算法小板报(四)——初探广义线性模型和最大熵模型
  6. Java08-java语法基础(七)构造方法
  7. Volcano:在离线作业混部管理平台,实现智能资源管理和作业调度
  8. 栈和队列之栈的定义和实现
  9. Linux C语言操作SQLite数据库
  10. 程序中变量分布的区域总结 堆 栈 字符常量区 全局数据区 静态存储区
  11. 微软下周将发布重磅安全公告 修复40个漏洞
  12. 在fedora linux中,wine 成功安装手记
  13. matlab plv,脑电脑网络分析代码使用流程介绍
  14. ps魔棒工具抠图和合成图
  15. 未来的外科手术可能由气泡代劳
  16. 晓之以理,不如动之以情——新书《以大致胜》解读(上篇)
  17. FISCO-BCOS学习——区块链浏览器搭建
  18. 《智慧彼岸之定心经》
  19. win10计算机性能选项在哪,Win10性能大提升,这些设置让你的电脑直接起飞
  20. mysql 导出gtid_mysqldump导出时 --set-gtid-purged=OFF

热门文章

  1. struts2注解json 配置文件json
  2. nohup不输出日志信息的方法,及linux重定向学习
  3. poj 1961 Period
  4. ASP.NET MVC 3 RC发布
  5. asp.net导出数据到Excel
  6. PRD文档范例,产品经理值得收藏的写作手册
  7. 「敏捷开发」适合什么样的团队?
  8. PMCAFF | 史上最完整的沙龙活动策划总结
  9. centos 7 密码破解 rm -rf 删除恢复
  10. ECSHOP去版权标志删除Powered by ECShop(转)