KeyValuePair<TKey,TValue>
每当我有成对相关的数据时,我通常都会使用该类型,因为一个是另一个的关键。如果数据不相关,那么Tuple<T1,T2>
类型更有意义,我会这样做。
现在我刚刚阅读了这篇关于为什么通常要避免KeyValuePair<TKey,TValue>
和偏爱的文章Tuple<T1,T2>
。主要论点是Tuple<T1,T2>
.
外部性能,有什么理由让 KVP 比 更好的选择Tuple<T1,T2>
?
好吧,这种类型可能被认为命名不当,例如。命名的 KeyValuePair 应该代表一个键和一个值。如果您的两个对象不是真正的键和值,只是两件事怎么办?如果我看到一个类型为 的方法或属性KeyValuePair<TKey, TValue>
,我希望 KVP 的值是键和值。这实际上只是沟通意图并在未来向自己或其他团队成员明确表示的问题。元组不表示那种关联。
元组还可以更容易地添加另一个值,使其成为 3 元组(或三元组,但你想调用它)。一些 .NET 语言,如 F#,也有围绕元组的特殊语法。
从实现的角度来看,Tuple
很多事情KeyValuePair
都没有。元组是可比较的,它们实现了IComparable
和IStructuralEquatable
接口,因此比较两个元组更容易。
KeyValuePair
是结构,Tuple
是一个类。
这是影响对象如何通过引用或值复制的主要区别。
因此Tuple<T1,T2>
在传递时只在 32 位操作系统中使用“4byte”,而KeyValuePair<K,V>
需要更多基于“K 和 V”
无论如何比较 Tuple 和 KeyValuePair 不是一个好主意(对我来说没有意义),因为两者都有不同的用途。
尽管存在语义,但在您考虑这两个选项时,性能可能是一个重要的考虑因素。如前所述,KeyValuePair
是值类型(结构),而Tuple<>
是引用类型(类)。因此,KeyValuePair
在栈上Tuple<>
分配,在堆上分配,最优选择通常由Stack vs. Heap Memory Allocation的经典论点决定。简而言之,堆栈空间是有限的,但通常访问速度非常快。堆内存要大得多,但速度要慢一些。
KeyValuePair<T1, T2>
int
如果键和值类型都是基元(值类型,如, bool
,double
等)或小尺寸结构,则可能是更好的选择。使用堆栈上的原始类型,分配和释放速度非常快。这确实会影响性能,尤其是作为递归方法调用的参数。
另一方面,Tuple<T1, T2>
如果 要么 要么 是引用类型(如类),则可能是更好的T1
选择T2
。包含指向引用类型(作为键或值类型)的指针的AKeyValuePair
有点违背了目的,因为无论如何都需要在堆上查找对象。
这是我在网上找到的一个基准:Tuple vs. 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 -- 返回 KeyValuePair2.79 ns -- 从列表中加载元组
4.18 ns -- 从列表中加载 KeyValuePair
你真的问错了问题,正确的问题是使用 Class(Tuple)_ 比 Struct(KVP) 更好,在这种情况下,答案就是你想用它们做什么,答案在这里给出Structs vs classes