Wann ist es besser, ein Tupel als ein KeyValuePair zu verwenden?

86

Ich habe den KeyValuePair<TKey,TValue>Typ im Allgemeinen immer dann verwendet, wenn ich Daten habe, die paarweise in dem Sinne sind, dass einer ein Schlüssel zum anderen ist. Wenn die Daten nicht in Beziehung stehen, ist der Tuple<T1,T2>Typ sinnvoller und ich würde damit weitermachen.

Jetzt habe ich gerade diesen Artikel darüber gelesen, warum man generell meidet KeyValuePair<TKey,TValue>und bevorzugt Tuple<T1,T2>. Das Hauptargument ist der Leistungsvorteil von Tuple<T1,T2>.

Gibt es einen Grund, warum ein KVP außerhalb der Leistung eine bessere Wahl wäre als ein Tuple<T1,T2>?

Nick Gotch
quelle
4
A KeyValuePairist ein Schlüssel und ein Wert, a Tuple<T1,T2>ist nur ein Paar gleicher Werte. Sie könnten auch fragen: "Warum sollte ich ein verwenden, List<Class>wenn ich verwenden kann Dictionary<A,B>".
Tim Schmelter
4
Richtig, aber in diesem Fall können Sie den Schlüssel zum Nachschlagen von Daten verwenden. Es bedeutet etwas. In diesem Fall sind die Namen nur Semantik, sie bedeuten nichts (für den Prozessor)
Nick Gotch
1
Ein Tupel ist kein Paar gleicher Werte, sondern eine Anzahl gleicher Typen. Vielleicht wird dies als Nitpicking angesehen, aber z. B. hat C das Vereinigungskonstrukt für verschiedene Darstellungen gleicher Werte. :)
Jonas

Antworten:

62

Nun, der Typ könnte zum einen als schlecht benannt angesehen werden. Ein KeyValuePair mit dem Namen sollte einen Schlüssel und einen Wert darstellen. Was ist, wenn Ihre beiden Objekte nicht wirklich ein Schlüssel und ein Wert sind, sondern nur zwei Dinge? Wenn ich eine Methode oder Eigenschaft sehen würde, die einen Typ von hat KeyValuePair<TKey, TValue>, würde ich erwarten, dass die Werte der KVP ein Schlüssel und ein Wert sind. Dies ist wirklich nur eine Frage der Kommunikation von Absichten und der Klärung gegenüber sich selbst oder möglicherweise anderen Teammitgliedern in der Zukunft. Ein Tupel zeigt diese Art von Assoziation nicht an.

Tupel erleichtern auch das Hinzufügen eines weiteren Werts, sodass es sich um ein 3-Tupel (oder ein Triplett, wie auch immer Sie es nennen möchten) handelt. Einige .NET-Sprachen wie F # haben auch eine spezielle Syntax für Tupel.

Für eine Implementierungsperspektive tun Tupleviele Dinge KeyValuePairnicht. Tupel sind vergleichbar, sie implementieren die Schnittstellen IComparableund und IStructuralEquatableerleichtern so den Vergleich zweier Tupel.

vcsjones
quelle
1
Ich habe herausgefunden, wie schwierig es ist, KeyValuePairs in ein Wörterbuch aufzunehmen, aber damals wird es nie ein Ergebnis geben.
MKesper
3
Darüber hinaus unterstützt das neue C # 7.0 eine neue, einfachere Syntax für Tupel, wodurch die Arbeit mit ihnen viel einfacher und leistungsfähiger ist als mit KeyValuePairs. visualstudiomagazine.com/articles/2017/01/01/…
Jacob Stamm
1
Die Möglichkeit, die Parameter in Tupeln zu benennen, erleichtert es dem Verbraucher, zu verstehen, wofür sie verwendet werden sollen. In einem Generikum wie KVP ist es wirklich jedermanns Vermutung - es sei denn, es ist irgendwo speziell dokumentiert -, was der Schlüssel "sein" soll - dh nicht sein Typ, sondern was für eine reale Sache es ist, wie ein Einstellungsname, ein soziales Sicherheitsnummer usw.
rory.ap
37

KeyValuePairist struct und Tupleist eine Klasse.

Dies ist der Hauptunterschied, der beeinflusst, wie die Objekte kopiert werden, sei es als Referenz oder als Wert.

und verwendet daher Tuple<T1,T2>bei Weitergabe nur "4 Byte" in 32-Bit-Betriebssystemen, während KeyValuePair<K,V>mehr basierend auf "K und V" erforderlich ist.

Der Vergleich von Tuple und KeyValuePair ist jedoch keine gute Idee (macht für mich keinen Sinn), da beide unterschiedlichen Zwecken dienen.

Sriram Sakthivel
quelle
2
Wie dienen sie einem anderen Zweck? Würden Sie bitte näher darauf eingehen?
OldSchool
1
@YakRangi keyvaluepair soll als Container für Schlüssel und Werte in einem Wörterbuch verwendet werden, andernfalls hat es keinen Zweck. Andererseits kann Tupel verwendet werden, um beliebig verwandte Mitglieder zusammen zu speichern. Auch mit Tuple können Sie mehrere Mitglieder zusammen speichern, nicht nur 2.
Sriram Sakthivel
@SriramSakthivel Dies bedeutet, dass die Antwort auf die OP-Frage lautet: Verwenden Sie kein KVP, es sei denn, Sie durchsuchen ein Wörterbuch.
Alex Fainshtein
23

Trotz der Semantik kann die Leistung eine wichtige Überlegung sein, wenn Sie beide Optionen in Betracht ziehen. Wie bereits erwähnt, KeyValuePairist das ein Werttyp (Struktur), während das Tuple<>ein Referenztyp (Klasse) ist. Daher wird das KeyValuePairauf dem Stapel und das Tuple<>auf dem Heap zugewiesen, und die optimale Auswahl wird normalerweise durch die klassischen Argumente Stack vs. Heap Memory Allocation bestimmt . Kurz gesagt, der Stapelspeicher ist begrenzt, hat aber im Allgemeinen einen sehr schnellen Zugriff. Der Heapspeicher ist viel größer, aber etwas langsamer.

KeyValuePair<T1, T2>die bessere Wahl sein , wenn sowohl der Schlüssel und Werttypen Primitive sind (Werttypen wie int, bool, doubleusw.) oder structs von geringer Größe. Mit primitiven Typen auf dem Stapel ist die Zuweisung und Freigabe blitzschnell. Dies kann die Leistung erheblich beeinträchtigen, insbesondere als Argumente für rekursive Methodenaufrufe.

Auf der anderen Seite Tuple<T1, T2>ist wahrscheinlich die bessere Wahl, wenn entweder T1oder T2sind Referenztypen (wie Klassen). A KeyValuePair, das Zeiger auf Referenztypen (als Schlüssel- oder Werttypen) enthält, macht den Zweck zunichte, da die Objekte ohnehin auf dem Heap nachgeschlagen werden müssen.

Hier ist ein Benchmark, den ich online gefunden habe: Tuple vs. KeyValuePair . Das einzige Problem mit diesem Benchmark ist , dass sie getestet KeyValuePair<string, string>vs. Tuple<string, string>und der stringTyp ist eine ungewöhnliche und besondere Art in .NET, dass sie beide wie ein Werttyp verhalten können und / oder einen Referenztyp auf dem Ausführungskontext abhängig. Ich glaube, das KeyValuePair<int, int>wäre ein klarer Sieger gewesen Tuple<int, int>. Trotz der Mängel zeigen die Ergebnisse jedoch, dass die Leistungsunterschiede erheblich sein können:

8,23 ns - Tupel zuweisen
0,32 ns - KeyValuePair zuweisen (25x schneller!)

1,93 ns - Tupel als Argument übergeben
2,57 ns - KeyValuePair als Argument übergeben

1,91 ns - Return Tuple
6,09 ns - Return KeyValuePair

2.79 ns - Tupel aus Liste
laden 4.18 ns - KeyValuePair aus Liste laden

Spezielle Sauce
quelle
0

Wenn Sie wirklich die falsche Frage stellen, verwendet die richtige Frage eine Klasse (Tupel) _ besser als eine Struktur (KVP). In diesem Fall lautet die Antwort, wofür Sie sie verwenden möchten, und die Antwort wird hier gegeben. Strukturen versus Klassen

MikeT
quelle
2
Er stellte die richtige Frage. Die Frage, welche für welche Verwendung besser ist, wird ausdrücklich impliziert.
Greg
@ Greg die Frage ist, welche Schokolade oder Soda besser ist, aber die spezifische Frage ist sinnlos und besser als allgemeine Frage zu Essen und Trinken
angesprochen
3
Die defacto Frage ist "Wann sollte ich Tuples Vs. KeyPairs verwenden?". Das ist eine berechtigte Frage. Ich denke, Sie bleiben nur bei der Semantik des Wortes "besser".
Greg