|
News:
|
class SomeClass
{
public string Text { get; set; }
}
static void Main(string[] args)
{
SomeClass newSomeClass = new SomeClass() { Text = "abc" };
Tuple<int, SomeClass> tuple1 = new Tuple<int, SomeClass>(5, newSomeClass);
Tuple<int, SomeClass> tuple2 = new Tuple<int, SomeClass>(5, new SomeClass() { Text = "abc" });
Tuple<int, SomeClass> tuple3 = new Tuple<int, SomeClass>(5, newSomeClass);
Console.WriteLine(tuple1 == tuple2); // false
Console.WriteLine(tuple1 == tuple3); // false
Console.WriteLine(tuple1.Equals(tuple2)); // false
Console.WriteLine(tuple1.Equals(tuple3)); // true
Console.ReadKey();
}
|
|
| 1 | ||
| 1 | ||
| 1 |
Danke. Ein Stück weit verstehe ich Dich jetzt besser. Aber Du hast einen Fehler in Deiner Argumentation. Wenn SomeClass Object.Equals(obj) implementiert, also insbesondere dann, wenn es IEquatable spezifikationsgemäß implementiert (MSDN: "Wenn Sie IEquatable<T>implementieren, müssen Sie auch die Implementierungen der Basisklasse von Object.Equals(Object) und GetHashCode überschreiben, sodass deren Verhalten dem der IEquatable<T>.Equals -Methode entspricht."), so ergibt tuple1.Equals(tuple2) true. [tbc...]
– Matthias Hlawatsch 09.09.2011
|
|
| 1 |
Und dann (und nur dann!) würde ich auch von einem einem eigenen Datentyp erwarten, dass zwei verschiedene Instanzen, die mit der selben Referenzen von SomeClass initialisiert wurden, "equal" sind. Von daher verhält sich Tuple meines Erachtens hier völlig korrekt und erwartungskonform.
P.S. Wenn Du das noch vertiefen willst, lass uns eine eigene Frage aufmachen, denn hier ging es ja nicht um Tuple, sondern um Dictionaries – Matthias Hlawatsch 09.09.2011
|
|
| 1 |
Genau das ist es. Da triffst Du den Nagel sowas von auf den Kopf. WENN es spezifikationsgemäß implementiert wird. Da gehören dann auch noch die Operatoren dazu,... bin ich voll bei Dir. Ein weiterer Grund, warum ich den eigenen Typ präferiere, so weiß ich wenigstens wo ich beim CodeReview hinschauen muss, im andern Fall muss ich danach suchen.
– ffordermaier 09.09.2011
|
|
| 1 |
Wieso? Du müßtest Dir in beiden Fällen SomeClass anschauen. Wenn dort jemand nur Equals(SomeClass), aber nicht Equals(Object) implementiert und Du das in Deinem eigenen Datentyp "kompensierst", dann versteckst Du einen Fehler und verschleierst das Problem. Du hättest dann den Fall, dass SomeClass als Einzel-Schlüssel sich anders verhalten würde als als Grundlage für Deinen eigenen Typ - das fände ich nun wiederum "hochgradig gefährlich".
– Matthias Hlawatsch 09.09.2011
|
|
| 1 |
Damit wir uns nicht falsch verstehen: einen eigenen Datentyp fände ich prinzipiell schon auch gut, vor allem wenn die Wertkombination irgendwas fachlich relevantes bedeutet, das man durch einen eigenen Namen gut ausdrücken kann. Aber Equals & Co. sollte er m.E. genau so implementieren wie die Tuple-Klasse. Und eh das jemand verbockt, lass ich ihn lieber Tuple verwenden.
– Matthias Hlawatsch 09.09.2011
|
|
| 1 |
Das meinte ich nicht. Es im eigenen Datentyp zu kompensieren ist ja noch schlimmer.
Klar muss ich den eigenen Datentyp (und natürlich alle damit einhergehenden, wie auch SomeClass) anschauen. Mit Suchen meinte ich das Auffinden der verstreuten Verwendung, die an sich nicht eindeutig ist. Ein zusammengesetzter Schlüssel Tuple<int, SomeClass> und Tuple<SomeClass,int> verhält sich gleich, hat dieselbe Semantik ist aber ein anderer Typ....[tbc] – ffordermaier 09.09.2011
|
|
| 1 |
Was ich letztendlich nur zum Ausdruck bringen will, ist, dass etwas zusammengesetztes fast immer einen eigenen Typ darstellt und einen sprechenden Namen verident, ob das ein Schlüssel oder eine Bestellung ist (die ist salopp fomuliert ja auch kein Tuple<Customer, List<Article>>). Ich glaub wir sind da letztlich derselben Meinung, nur die Qualität der Erfahrung mit solchen Dingen verschiebt die Toleranzgrenze marginal.
Danke auf alle Fälle für den Meinungsaustausch! Das ist mir viel wert, dass das hier auf codekicker so unkomliziert geht. Auch wenn Kommentare eher ungeeignet sind. – ffordermaier 09.09.2011
|
|
| 1 |
In meiner Antwort verweise ich auf folgenden Link bei SO: http://stackoverflow.com/questions/1171812/multi-key-dictionary-in-c/1171869#1171869
Hier wollte ich (ein wenig) Bezug auf Matthias Kommentar nehmen. Gleich der erste Kommentar führt zu folgendem Link, der IMO zu eurer Diskussion passt: http://msdn.microsoft.com/en-us/magazine/dd942829.aspx#id0400060 – Jürgen Luhr 09.09.2011
|
|
| 3 | ||
|
@Jürgen, danke für den Hinweis auf den Link im verlinkten Beitrag. Das muss ich mir morgen mal genau anschauen.
– ffordermaier 09.09.2011
|
||
|
Danke für die ausführliche Darstellung. Ich habe eine große Liste von Items und benötige ein "MultiKeyDictionary" um performant über 2 Schlüssel das entsprechende Item zu bekommen. Da die Schlüssel immer primitive Typen sind kann ich guten Gewissens ein Tuple verwenden. Ich glaube ein guter Kompromiss (als Alternative zum eigenen Schlüsseltyp) ist, wenn das Tupel über eine Methode erzeugt wird.
– Tachyon 10.09.2011
|
||
|
Hallo Tachyon, freut mich, dass wir Dir helfen konnten. Ich habe meine Antwort gerade nochmal erweitert, auch mit ein paar Gedanken zur Performance.
– Matthias Hlawatsch 12.09.2011
|
In our first draft of the tuple specification, we kept the two-, three-, and four-element tuples as value types, with the rest being reference types. However, during a design meeting that included representatives from other languages it was decided that this "split" design would be confusing, due to the slightly different semantics between the two types. Consistency in behavior and design was determined to be of higher priority than potential performance increases.
|
|
|
Steh ich grad auf dem Schlauch, oder warum definiert der sich dort über ein halbes Jahr nach Erscheinen von .NET 4.0 noch seinen eigenen Tuple-Typ?
– Matthias Hlawatsch 09.09.2011
|
||
|
Evt. verwendet er noch ein altes Framework aus Kompatibilitätsgründen zu alten Betriebsystemen?!? Das weiß nur Er.
– Jürgen Luhr 09.09.2011
|
var value = dict[key1][key2];
dict[key1][key2] = value;
class CompositeKeyDictionary<TKey1, TKey2, Value> : Dictionary<TKey1, Dictionary<TKey2, TValue>> {...}dict.ContainsKey(key1).ContainsKey(key2)liest sich nicht so toll, von der Add-Methode ganz zu schweigen. Durch eigene Methoden (ContainsKey(key1, key2) usw.) läßt sich das aber schön beheben.
|
|
|
Schönes Update im Nachhinein! Die gesammelten Antworten und Kommentare beleuchten die Frage aus vielen Perspektiven. Hat Spass gemacht.
– ffordermaier 12.09.2011
|
Zumindest GetHashCode und Equals (und im übrigen sogar IComparable) bringt auch schon die Tuple-Klasse mit, weshalb sich allein daraus für mich noch keine Berechtigung für einen eigenen Datentyp ableitet.