Quand est-il préférable d'utiliser un Tuple par rapport à un KeyValuePair?

90

J'ai généralement utilisé le KeyValuePair<TKey,TValue>type chaque fois que j'ai des données liées à des paires dans le sens où l'une est une clé pour l'autre. Si les données ne sont pas liées, le Tuple<T1,T2>type a plus de sens et j'irais avec ça.

Maintenant, je viens de lire cet article sur les raisons pour lesquelles il faut généralement éviter KeyValuePair<TKey,TValue>et préférer Tuple<T1,T2>. Le principal argument étant l'avantage de performance de Tuple<T1,T2>.

En dehors des performances, y a-t-il une raison pour laquelle un KVP serait un meilleur choix qu'un Tuple<T1,T2>?

Nick Gotch
la source
4
A KeyValuePairest une clé et une valeur, a Tuple<T1,T2>est juste une paire de valeurs égales . Vous pouvez également demander: "pourquoi devrais-je utiliser un List<Class>si je peux utiliser Dictionary<A,B>".
Tim Schmelter
4
Bien, mais dans ce cas, vous pouvez utiliser la clé pour rechercher des données. Cela signifie quelque chose. Dans ce cas, les noms ne sont que de la sémantique, ils ne signifient rien (pour le processeur.)
Nick Gotch
1
Un tuple n'est pas une paire de valeurs égales, mais un certain nombre de types égaux. Peut-être que cela est considéré comme un pinaillage, mais par exemple, C a la construction d'union pour différentes représentations de valeurs égales. :)
Jonas

Réponses:

65

Eh bien, le type pourrait être considéré comme mal nommé, par exemple. Un KeyValuePair tel que nommé doit représenter une clé et une valeur. Et si vos deux objets ne sont pas vraiment une clé et une valeur, juste deux choses? Si je devais voir une méthode ou une propriété qui avait un type de KeyValuePair<TKey, TValue>, je m'attendrais à ce que les valeurs du KVP soient une clé et une valeur. Il s'agit simplement de communiquer l'intention et de la faire comprendre à vous-même à l'avenir, ou éventuellement à d'autres membres de l'équipe. Un tuple n'indique pas ce type d'association.

Les tuples facilitent également l'ajout d'une autre valeur, ce qui en fait un 3-tuple (ou un triplet, comme vous voulez l'appeler). Certains langages .NET, comme F #, ont également une syntaxe spéciale autour des tuples.

Pour une perspective de mise en œuvre, Tuplebeaucoup de choses KeyValuePairne le font pas. Les tuples sont comparables, ils implémentent les interfaces IComparableet IStructuralEquatable, ce qui facilite la comparaison de deux tuples.

vcsjones
la source
1
J'ai découvert à la dure que vous pouvez mettre KeyValuePairs dans un dictionnaire mais que vous n'obtiendrez jamais de résultat à l'époque.
MKesper
3
En outre, le nouveau C # 7.0 prend en charge une nouvelle syntaxe plus simple pour les tuples, ce qui les rend beaucoup plus faciles et plus performants à utiliser que KeyValuePairs. visualstudiomagazine.com/articles/2017/01/01/…
Jacob Stamm
1
En outre, la possibilité de nommer les paramètres en tuples permet au consommateur de comprendre plus facilement à quoi ils sont censés être utilisés. Dans un générique comme KVP, c'est vraiment n'importe qui devine - à moins qu'il ne soit spécifiquement documenté quelque part - ce que la clé est censée "être" - c'est-à-dire pas son type mais ce que c'est du monde réel, comme un nom de paramètre, un social numéro de sécurité, etc.
rory.ap
40

KeyValuePairest struct et Tupleest une classe.

C'est la principale différence qui influence la manière dont les objets sont copiés que ce soit par référence ou par valeurs.

et par conséquent, Tuple<T1,T2>lorsqu'il est transmis, il utilise simplement "4 octets" dans le système d'exploitation 32 bits, alors qu'il en KeyValuePair<K,V>faut plus basé sur "K et V"

Quoi qu'il en soit, comparer Tuple et KeyValuePair n'est pas une bonne idée (cela n'a pas de sens pour moi) car les deux servent des objectifs différents.

Sriram Sakthivel
la source
2
Comment servent-ils un objectif différent? pourriez-vous s'il vous plaît élaborer sur cela
OldSchool
1
@YakRangi keyvaluepair est destiné à être utilisé comme conteneur pour les clés et les valeurs d'un dictionnaire, sinon, cela ne sert à rien. D'autre part, Tuple peut être utilisé pour stocker ensemble tous les membres liés arbitrairement. Aussi avec Tuple, vous pouvez stocker plusieurs membres combinés, pas seulement 2.
Sriram Sakthivel
@SriramSakthivel Cela signifie que la réponse à la question OP est: n'utilisez pas KVP, sauf si vous parcourez un dictionnaire.
Alex Fainshtein
23

Malgré la sémantique, les performances peuvent être une considération importante lorsque vous envisagez les deux options. Comme mentionné précédemment, the KeyValuePairest un type valeur (struct), tandis que the Tuple<>est un type référence (classe). Par conséquent, le KeyValuePairest alloué sur la pile et le Tuple<>est alloué sur le tas, et le choix optimal est généralement déterminé par les arguments classiques de l' allocation de mémoire pile ou tas . En bref, l'espace de pile est limité, mais a généralement un accès très rapide. La mémoire du tas est beaucoup plus grande mais est un peu plus lente.

KeyValuePair<T1, T2>peut être le meilleur choix si les deux types de clés et la valeur sont primitives (types de valeur comme int, bool, double, etc.) ou struct de petite taille. Avec les types primitifs sur la pile, l'allocation et la désallocation sont rapides comme l'éclair. Cela peut vraiment affecter les performances, en particulier en tant qu'arguments aux appels de méthode récursifs.

D'autre part, Tuple<T1, T2>est probablement le meilleur choix si l'un T1ou l' autre T2des types de référence (comme les classes). Un KeyValuePairqui contient des pointeurs vers des types de référence (comme les types de clé ou de valeur) va en quelque sorte à l'encontre de l'objectif puisque les objets devront de toute façon être recherchés sur le tas.

Voici un benchmark que j'ai trouvé en ligne: Tuple vs KeyValuePair . Le seul problème avec ce benchmark est qu'ils ont testé KeyValuePair<string, string>contre Tuple<string, string>, et le stringtype est un type inhabituel et spécial dans .NET en ce qu'il peut se comporter à la fois comme un type valeur et / ou un type référence en fonction du contexte d'exécution. Je crois que l' KeyValuePair<int, int>aurait été un vainqueur clair contre Tuple<int, int>. Cependant, même avec les lacunes, les résultats montrent que les différences de performance peuvent être importantes:

8.23 ns - Allocate Tuple
0.32 ns - Allocate KeyValuePair (25x plus rapide!)

1,93 ns - Passez Tuple comme argument
2,57 ns - Passez KeyValuePair comme argument

1,91 ns -
Tuple de retour 6,09 ns - Retour KeyValuePair

2.79 ns - Charger le tuple de la liste
4.18 ns - Charger la KeyValuePair depuis la liste

Sauce spéciale
la source
0

Vous posez vraiment la mauvaise question, la bonne question consiste à utiliser une classe (Tuple) _ mieux qu'un Struct (KVP), auquel cas la réponse est à quoi voulez-vous les utiliser et la réponse est donnée ici Structs versus classes

MikeT
la source
2
Il a posé la bonne question. La question de savoir quel est le meilleur pour quel usage est explicitement implicite.
Greg
La question est @ Greg qui est mieux, mais la question spécifique du chocolat ou de la soude est inutile et mieux traitée comme une question générale sur les aliments et les boissons
MikeT
3
La question de facto est "Quand devrais-je utiliser Tuples Vs. KeyPairs?". C'est une question légitime. Je pense que vous êtes juste coincé sur la sémantique du mot «mieux».
Greg