111 votes

Quand est-il préférable d'utiliser un Tuple plutôt qu'un KeyValuePair?

J'ai généralement utilisé le type KeyValuePair chaque fois que j'ai des données qui sont liées par paires dans le sens où l'une est une clé pour l'autre. Si les données ne sont pas liées, alors le type Tuple est plus logique et j'irais avec celui-ci.

Maintenant, je viens de lire cet article sur pourquoi il vaut mieux éviter généralement KeyValuePair et préférer Tuple. L'argument principal étant le bénéfice de performance de Tuple.

En dehors des performances, est-ce qu'il y a une raison pour laquelle un KVP serait un meilleur choix qu'un Tuple ?

82voto

vcsjones Points 51910

Eh bien, le type pourrait être considéré comme mal nommé, pour commencer. Un KeyValuePair devrait représenter une clé et une valeur. Que se passe-t-il 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, je m'attendrais à ce que les valeurs de la KVP soient une clé et une valeur. Il s'agit vraiment simplement de communiquer l'intention et de la rendre claire pour vous-même à l'avenir, ou éventuellement pour d'autres membres de l'équipe. Un tuple ne donne pas ce genre d'indication.

Les tuples permettent également d'ajouter plus facilement une autre valeur, transformant ainsi le tuple en 3-tuple (ou triplet, comme vous préférez l'appeler). Certains langages .NET, comme F#, ont une syntaxe spéciale autour des tuples également.

Du point de vue de l'implémentation, Tuple fait beaucoup de choses que KeyValuePair ne fait pas. Les tuples sont comparables, ils implémentent les interfaces IComparable et IStructuralEquatable, ce qui facilite la comparaison de deux tuples.

45voto

Sriram Sakthivel Points 33463

KeyValuePair est une structure et Tuple est une classe.

C'est la principale différence qui influe sur la façon dont les objets sont copiés, que ce soit par référence ou par valeurs.

et donc Tuple lorsqu'il est passé autour utilise simplement "4 octets" dans un OS 32 bits, tandis que KeyValuePair nécessite plus en fonction de "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 fins différentes.

35voto

Special Sauce Points 1341

Malgré la sémantique, la performance peut être une considération importante lorsque vous envisagez les deux options. Comme mentionné précédemment, le KeyValuePair est un type de valeur (struct), tandis que le Tuple<> est un type de référence (class). Par conséquent, le KeyValuePair est 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 Allocation de mémoire sur la pile vs. le tas. En bref, l'espace de la 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 peut être le meilleur choix si les types de clé et de valeur sont des types primitifs (types de valeur comme int, bool, double, etc.) ou des structs de petite taille. Avec des types primitifs sur la pile, l'allocation et la libération sont ultra rapides. Cela peut vraiment affecter les performances, surtout en tant qu'arguments pour des appels de méthode récursive.

D'autre part, Tuple est probablement le meilleur choix si l'un des types T1 ou T2 est un type de référence (comme les classes). Un KeyValuePair qui contient des pointeurs vers des types de référence (en tant que types de clé ou de valeur) va à l'encontre du but recherché 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 vs. Tuple, et le type string est un type inhabituel et spécial dans .NET en ce sens qu'il peut se comporter à la fois comme un type de valeur et/ou un type de référence en fonction du contexte d'exécution. Je pense que KeyValuePair aurait été clairement gagnant contre Tuple. Malgré les lacunes, cependant, les résultats montrent que les différences de performances peuvent être significatives :

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

1.93 ns -- Passer Tuple en argument
2.57 ns -- Passer KeyValuePair en argument

1.91 ns -- Renvoyer Tuple
6.09 ns -- Renvoyer KeyValuePair

2.79 ns -- Charger Tuple depuis la liste
4.18 ns -- Charger KeyValuePair depuis la liste

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X