CSharp中的元组(Tuple)以及动态类型(Dynamic)的介绍

很多程序员其实没有用过“元组”和动态类型,包括我在内!当一个方法需要一次性返回多个参数时,我会选择用键值对数组或者其他对象的方式。并且,在方法入参时,其实使用out和ref关键字的方式也可以达到一次返回多个参数值的要求。

但是,有朋友建议我使用元组(Tuple)和动态类型(dynamic)!虽然我不建议您使用这两种类型,但是我也挺听劝,既然有人想知道,我不妨就介绍介绍这两个类型。

以我的常用语言C#为例,可能有些地方跟C++或者Java封装得不一样,但其实本质是一样的!

Tuple分两种,另外一种叫作值元组(ValueTuple),两者“师出同门”,均继承自ITuple,区别是前者为引用类型,后者为值类型,作为值类型,从执行效率上讲会更高一点。

而Tuple的用法很简单,Tuple提供了1到8个参数的静态泛型重载,即在定义Tuple时,可以使用Tuple的8个静态方法来定义Tuple的长度,其中,第8个参数为用来扩展长度的Tuple类型,当前面7个参数不够用的时候,则可以再构建一个Tuple来扩展长度,以实现参数的无限度返回!原理类似多维数组。

元组普通用法
元组扩充字段用法

从时间维度上讲,C#的Tuple的历史要早于ValueTuple,其实两者的用法,除了关键字,区别并不大。但是为什么C#又要在后来弄出一个VaueTuple呢?其实道理也很简单,那就是Tuple的元素值是只读的!

而ValueTuple的一个更大的优势在于,ValueTuple的元素是可变的。与Tuple一样,ValueTuple的同样支持1到8个参数的静态泛型重载,第8个参数为TRest,只接受ValueTuple类型的参数。

值元组用法TRest

在常规使用ValueTuple前7个参数时,获取元素的方式为ValueTuple.Item1…Item7,当然了,Tuple获取元素的方式也是一样的。但是,当获取TRest元素时,您会发现,ValueTuple会根据TRest内的参数长度自动扩充字段item8、item9、item10…

但是,Tuple和ValueTuple都有一个共同的缺点,那就是不管是Tuple的属性还是ValueTuple的字段,都是根据下标而定义的元素“item”。如果我们在外部调用它们,我们还需要根据元素的下标来判断这个元素到底代表着什么意思,可读性比较差!

所以,在C#的方法返回参数时,还提供了ValueTuple的简易写法,即使用括号“()”,以逗号分隔的方式返回参数,并且也支持TRest的方式返回,即可以返回无限长度的参数(虽然不建议这么用)。然后在接收参数时,可以以自定义变量的形式接收参数的值。

值元组在方法中的简易写法

因此,从执行效率和代码结构上讲,ValueTuple比Tuple效率更高、代码结构更清晰、更易用!

相对于Tuple的属性名、ValueTuple的字段名不能完整表达值的意思,dynamic则可以完全规避这一点!至于dynamic,在C#中叫作动态类型或者称之为匿名对象,即不需要预先定义的类型。好处如其名,就是不需要预先定义对象的结构。可以让我们在定义、返回对象的时候,可以根据实际情况构建对象字段。

动态对象用法

但是,dynamic有个天生的劣势,那就是dynamic是在运行时才会确定内容的。在编译的时候,如果一不小心把dynamic的字段写错了,并不影响编译,程序运行时如果发现dynamic中不存在使用的字段,程序就会报错!

动态对象的缺陷

因为运行时才会确定内容,因此若构建的dynamic对象太大,则会影响程序的执行效率。

所以,若真的要用dynamic动态类型,那么我的建议是dynamic的结构不宜太过复杂!

举报/反馈