Quando é melhor usar uma tupla em vez de um KeyValuePair?

91

Geralmente, uso o KeyValuePair<TKey,TValue>tipo sempre que tenho dados relacionados aos pares, no sentido de que um é a chave para o outro. Se os dados não estiverem relacionados, o Tuple<T1,T2>tipo faz mais sentido e eu aceitaria isso.

Acabei de ler este artigo sobre por que geralmente evitar KeyValuePair<TKey,TValue>e preferir Tuple<T1,T2>. O principal argumento é o benefício de desempenho de Tuple<T1,T2>.

Desempenho externo, há algum motivo pelo qual um KVP seria uma escolha melhor do que um Tuple<T1,T2>?

Nick Gotch
fonte
4
A KeyValuePairé uma chave e um valor, a Tuple<T1,T2>é apenas um par de valores iguais . Você também pode perguntar: "por que devo usar um List<Class>se eu posso usar Dictionary<A,B>".
Tim Schmelter,
4
Certo, mas nesse caso você pode usar a chave para pesquisar dados. Isso significa algo. Nesse caso, os nomes são apenas semânticos, eles não significam nada (para o processador).
Nick Gotch
1
Uma tupla não é um par de valores iguais, mas um certo número de tipos iguais. Talvez isso seja visto como picuinhas, mas, por exemplo, C tem a construção de união para diferentes representações de valores iguais. :)
Jonas

Respostas:

68

Bem, o tipo pode ser considerado mal nomeado, por exemplo. Um KeyValuePair conforme nomeado deve representar uma chave e um valor. E se seus dois objetos não forem realmente uma chave e um valor, apenas duas coisas? Se eu visse um método ou propriedade que tivesse um tipo deKeyValuePair<TKey, TValue> , esperaria que os valores do KVP fossem uma chave e um valor. Na verdade, é apenas uma questão de comunicar a intenção e deixar isso claro para você mesmo ou, possivelmente, para outros membros da equipe. Uma tupla não indica esse tipo de associação.

As tuplas também facilitam a adição de outro valor, tornando-o um 3-tupla (ou um trio, como você quiser chamá-lo). Algumas linguagens .NET, como F #, têm sintaxe especial em torno das tuplas também.

Para uma perspectiva de implementação, Tuplemuitas coisas KeyValuePairnão fazem. As tuplas são comparáveis, elas implementam as interfaces IComparablee IStructuralEquatable, portanto, torna mais fácil comparar duas tuplas.

vcsjones
fonte
1
Eu descobri da maneira mais difícil que você pode colocar KeyValuePairs em um dicionário, mas nunca obterá um resultado naquela época.
MKesper
3
Além disso, o novo C # 7.0 oferece suporte à sintaxe nova e mais simples para tuplas, tornando-os muito mais fáceis e eficientes de se trabalhar do que os KeyValuePairs. visualstudiomagazine.com/articles/2017/01/01/…
Jacob Stamm
1
Além disso, a capacidade de nomear os parâmetros em tuplas torna mais fácil para o consumidor entender para que eles devem ser usados. Em um genérico como KVP, ninguém pode adivinhar - a menos que seja especificamente documentado em algum lugar - o que a chave deve "ser" - ou seja, não o seu tipo, mas que coisa do mundo real é, como um nome de configuração, um número de segurança, etc.
rory.ap
40

KeyValuePairé struct e Tupleé uma classe.

Essa é a principal diferença que influencia como os objetos são copiados seja por referência ou por valores.

e, portanto, Tuple<T1,T2>quando transmitido apenas usa "4byte" no sistema operacional de 32 bits, enquanto KeyValuePair<K,V>requer mais com base em "K e V"

De qualquer forma, comparar Tuple e KeyValuePair não é uma boa ideia (não faz sentido para mim), pois ambos servem a propósitos diferentes.

Sriram Sakthivel
fonte
3
Como eles servem a um propósito diferente? você poderia elaborar sobre isso.
OldSchool de
2
@YakRangi keyvaluepair deve ser usado como um contêiner para chaves e valores em um dicionário, caso contrário, não tem nenhum propósito. Por outro lado, Tupla pode ser usada para armazenar juntos quaisquer membros arbitrariamente relacionados. Além disso, com Tuple, você pode armazenar vários membros combinados não apenas 2.
Sriram Sakthivel
1
@SriramSakthivel Isso significa que a resposta à pergunta do OP é: não use KVP, a menos que esteja navegando em um Dicionário.
Alex Fainshtein
24

Apesar da semântica, o desempenho pode ser uma consideração importante quando você considera as duas opções. Conforme mencionado anteriormente, o KeyValuePairé um tipo de valor (estrutura), enquanto o Tuple<>é um tipo de referência (classe). Portanto, o KeyValuePairé alocado na pilha e o Tuple<>é alocado no heap, e a escolha ideal geralmente é determinada pelos argumentos clássicos de Stack vs. Heap Memory Allocation . Resumindo, o espaço da pilha é limitado, mas geralmente tem acesso muito rápido. A memória heap é muito maior, mas um pouco mais lenta.

KeyValuePair<T1, T2>pode ser a escolha melhor se tanto a chave e valor tipos são primitivos (tipos de valor, como int, bool, double, etc.) ou estruturas de pequena dimensão. Com tipos primitivos na pilha, a alocação e desalocação são extremamente rápidas. Isso pode realmente afetar o desempenho, especialmente como argumentos para chamadas de método recursivas.

Por outro lado, Tuple<T1, T2>é provavelmente a melhor escolha se T1ou T2forem tipos de referência (como classes). Um KeyValuePairque contém ponteiros para tipos de referência (como os tipos de chave ou valor) meio que anula o propósito, pois os objetos precisarão ser pesquisados ​​no heap de qualquer maneira.

Aqui está um benchmark que encontrei online: Tuple vs. KeyValuePair . O único problema com esse benchmark é que eles testaram KeyValuePair<string, string>vs. Tuple<string, string>, e o stringtipo é um tipo incomum e especial no .NET, pois pode se comportar como um tipo de valor e / ou um tipo de referência dependendo do contexto de execução. Eu acredito que o KeyValuePair<int, int>teria sido um claro vencedor contra Tuple<int, int>. Mesmo com as deficiências, no entanto, os resultados mostram que as diferenças de desempenho podem ser significativas:

8,23 ns - Alocar Tupla
0,32 ns - Alocar KeyValuePair (25x mais rápido!)

1,93 ns - Passe Tupla como argumento
2,57 ns - Passe KeyValuePair como argumento

1,91 ns - Tupla de retorno
6,09 ns - Return KeyValuePair

2,79 ns - Carregar Tupla da Lista
4,18 ns - Carregar KeyValuePair da Lista

Molho Especial
fonte
0

Você realmente está fazendo a pergunta errada, a pergunta apropriada é usar uma Classe (Tupla) _ melhor do que uma Struct (KVP), caso em que a resposta é para que você deseja usá-los e a resposta é dada aqui Structs versus classes

MikeT
fonte
2
Ele fez a pergunta certa. A questão de qual é melhor para qual uso está explicitamente implícito.
Greg
@Greg, a questão é qual é o melhor chocolate ou refrigerante, no entanto, a questão específica não tem sentido e é melhor abordada como uma questão geral sobre comida e bebida
MikeT
3
A pergunta de fato é "Quando devo usar tuplas contra pares de chaves?". Esta é uma pergunta legítima. Acho que você está preso na semântica da palavra "melhor".
Greg