什么时候使用元组和KeyValuePair更好?


90

通常,KeyValuePair<TKey,TValue>只要我拥有与数据对相关的数据,就使用一种类型,因为一个是另一个的关键。如果数据不相关,则Tuple<T1,T2>类型更有意义,我会考虑。

现在,我只读了这篇文章,了解为什么通常要避免KeyValuePair<TKey,TValue>和偏爱Tuple<T1,T2>。主要的争论是绩效的收益Tuple<T1,T2>

外部表现,有什么理由比KVP更好Tuple<T1,T2>


4
AKeyValuePair是键和值,aTuple<T1,T2>只是一对相等的值。您也可能会问:“List<Class>如果可以使用,为什么要使用a Dictionary<A,B>”。
蒂姆·施密特

4
对,但是在那种情况下,您可以使用键来查找数据。这意味着什么。在这种情况下,名字只是语义,他们没有任何意义(到处理器。)
尼克Gotch

1
元组不是一对相等的值,而是一定数量的相等的类型。也许这被视为挑剔,但例如C确实具有用于相等值的不同表示形式的并集构造。:)
乔纳斯(Jonas)

Answers:


64

好吧,该类型可以被认为是名字不好的一个。名为KeyValuePair的名称应表示一个键和一个值。如果您的两个对象实际上不是键和值,仅仅是两件事怎么办?如果我看到类型为的方法或属性,则KeyValuePair<TKey, TValue>希望KVP的值是键和值。这实际上只是沟通意图并在将来向自己或其他团队成员明确表示问题。元组不表示这种关联。

元组还使添加另一个值变得更容易,使它成为3元组(或三元组,不过您想调用它)。某些.NET语言(例如F#)具有特殊的语法在元组周围。

从实现的角度来看,Tuple很多事情KeyValuePair没有。元组具有可比性,它们实现IComparableIStructuralEquatable接口,因此可以更轻松地比较两个元组。


1
我发现很难将KeyValuePairs放入字典中的方法,但那时再也不会得到结果。
MKesper '16

3
此外,新的C#7.0支持元组的新的,更简单的语法,与KeyValuePairs相比,它们更易于使用性能更高。visualstudiomagazine.com/articles/2017/01/01/...
雅各布斯塔姆

1
同样,以元组命名参数的能力使消费者更容易理解它们的用途。在像KVP这样的通用名称中,真的是每个人都在猜测-除非在某处专门记录了-密钥应该是什么-即不是密钥的类型,而是真实的东西,例如设置名称,社交名安全号码等
rory.ap

40

KeyValuePair是struct,Tuple是一个类。

那是主要的差异,这会影响通过引用还是通过值复制对象的方式。

因此Tuple<T1,T2>在32位操作系统中传递时仅使用“ 4byte”,而KeyValuePair<K,V>基于“ K和V”则需要更多

无论如何,比较Tuple和KeyValuePair并不是一个好主意(对我而言这没有意义),因为两者都有不同的用途。


2
它们如何达到不同的目的?请您详细说明一下。
OldSchool

1
@YakRangi键值对旨在用作字典中键和值的容器,否则它没有任何作用。另一方面,元组可用于将任何任意相关的成员存储在一起。另外随着元组可以存储多个成员结合不只是2
斯利拉姆Sakthivel

@SriramSakthivel这意味着,OP问题的答案是:不要使用KVP,除非您正在浏览字典。
Alex Fainshtein

23

尽管具有语义,但是在您同时考虑这两个选项时,性能可能是一个重要的考虑因素。如前所述,KeyValuePair是值类型(结构),而是Tuple<>引用类型(类)。因此,KeyValuePair分配在堆栈上,Tuple<>分配在堆上,最佳选择通常由堆栈与堆内存分配的经典参数确定。简而言之,堆栈空间有限,但通常访问速度非常快。堆内存要大得多,但要慢一些。

KeyValuePair<T1, T2>可能是更好的选择,如果这两个键和值的类型是基元(值类型喜欢intbooldouble等),或小尺寸的结构。在堆栈上使用原始类型时,分配和取消分配的速度很快。这确实会影响性能,尤其是作为递归方法调用的参数时。

在另一方面,Tuple<T1, T2>很可能是更好的选择,如果任一T1T2是引用类型(如类)。KeyValuePair包含指向引用类型(作为键或值类型)的指针的A达不到目的,因为无论如何都需要在堆上查找对象。

这是我在网上找到的基准:Tuple与KeyValuePair。该基准测试的唯一问题是他们测试了KeyValuePair<string, string>vs. Tuple<string, string>,并且该string类型在.NET中是一种不寻常的特殊类型,因为它可以根据执行上下文而像值类型和/或引用类型一样工作。我相信那KeyValuePair<int, int>将是反对的明显赢家Tuple<int, int>。但是,即使存在缺陷,结果也表明性能差异可能非常明显:

8.23 ns-分配元组
0.32 ns-分配KeyValuePair (快25倍!)

1.93 ns-将Tuple作为参数
传递2.57 ns-将KeyValuePair作为参数传递

1.91 ns-返回元组
6.09 ns-返回KeyValuePair

2.79 ns-从列表中加载元组
4.18 ns-从列表中加载KeyValuePair


0

您确实提出了错误的问题,正确的问题是使用Class(Tuple)_优于Struct(KVP),在这种情况下,is答案是您要使用它们的目的,答案在此处给出Structs与类


2
他问了正确的问题。对于明确隐含的用法,哪个问题更好。
格雷格

@Greg问题是哪个是更好的巧克力或苏打水,但是作为食品和饮料的一般性问题,这个特定的问题是没有意义的,可以更好地解决
MikeT

3
事实上的问题是“我何时应该使用Tuples Vs. KeyPairs?”。这是一个合理的问题。我认为您只是停留在“更好”一词的语义上。
格雷格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.