Zusammengesetztes Schlüsselwörterbuch

88

Ich habe einige Objekte in List, sagen wir, List<MyClass>und MyClass hat mehrere Eigenschaften. Ich möchte einen Index der Liste basierend auf 3 Eigenschaften von MyClass erstellen. In diesem Fall sind 2 der Eigenschaften int und eine Eigenschaft ist eine Datums- / Uhrzeitangabe.

Grundsätzlich möchte ich in der Lage sein, etwas zu tun wie:

Dictionary< CompositeKey , MyClass > MyClassListIndex = Dictionary< CompositeKey , MyClass >();
//Populate dictionary with items from the List<MyClass> MyClassList
MyClass aMyClass = Dicitonary[(keyTripletHere)];

Manchmal erstelle ich mehrere Wörterbücher in einer Liste, um verschiedene Eigenschaften der darin enthaltenen Klassen zu indizieren. Ich bin mir jedoch nicht sicher, wie ich mit zusammengesetzten Schlüsseln am besten umgehen soll. Ich habe überlegt, eine Prüfsumme der drei Werte zu erstellen, aber dies birgt das Risiko von Kollisionen.

AaronLS
quelle
2
Warum benutzt du keine Tupel? Sie erledigen das Compositing für Sie.
Eldritch Conundrum
20
Ich weiß nicht, wie ich darauf reagieren soll. Sie stellen diese Frage, als hätten Sie angenommen, dass ich Tupel absichtlich vermeide.
AaronLS
6
Entschuldigung, ich habe es als detailliertere Antwort umgeschrieben.
Eldritch Conundrum
1
Bevor Sie eine benutzerdefinierte Klasse implementieren, lesen Sie mehr über Tuple (wie von Eldritch Conundrum vorgeschlagen) - msdn.microsoft.com/en-us/library/system.tuple.aspx . Sie sind einfacher zu ändern und ersparen Ihnen die Erstellung benutzerdefinierter Klassen.
Arbeitsschutz

Antworten:

102

Sie sollten Tupel verwenden. Sie entsprechen einer CompositeKey-Klasse, aber Equals () und GetHashCode () sind bereits für Sie implementiert.

var myClassIndex = new Dictionary<Tuple<int, bool, string>, MyClass>();
//Populate dictionary with items from the List<MyClass> MyClassList
foreach (var myObj in myClassList)
    myClassIndex.Add(Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString), myObj);
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];

Oder mit System.Linq

var myClassIndex = myClassList.ToDictionary(myObj => Tuple.Create(myObj.MyInt, myObj.MyBool, myObj.MyString));
MyClass myObj = myClassIndex[Tuple.Create(4, true, "t")];

Sofern Sie die Berechnung des Hash nicht anpassen müssen, ist die Verwendung von Tupeln einfacher.

Wenn Sie viele Eigenschaften in den zusammengesetzten Schlüssel aufnehmen möchten, kann der Name des Tupeltyps ziemlich lang werden. Sie können den Namen jedoch kürzer machen, indem Sie eine eigene Klasse erstellen, die von Tupel <...> abgeleitet ist.


** bearbeitet im Jahr 2017 **

Es gibt eine neue Option, die mit C # 7 beginnt: die Wertetupel . Die Idee ist dieselbe, aber die Syntax ist anders, leichter:

Der Typ Tuple<int, bool, string>wird (int, bool, string)und der Wert Tuple.Create(4, true, "t")wird (4, true, "t").

Mit Wertetupeln wird es auch möglich, die Elemente zu benennen. Beachten Sie, dass sich die Leistungen geringfügig unterscheiden. Sie können daher ein Benchmarking durchführen, wenn dies für Sie von Bedeutung ist.

Eldritch Rätsel
quelle
4
Tupel ist kein guter Kandidat für einen Schlüssel, da es eine hohe Anzahl von Hash-Kollisionen erzeugt. stackoverflow.com/questions/12657348/…
Paparazzo
1
@Blam KeyValuePair<K,V>und andere Strukturen haben eine Standard-Hash-Funktion, von der bekannt ist, dass sie fehlerhaft ist ( weitere Informationen finden Sie unter stackoverflow.com/questions/3841602/… ). Tuple<>ist jedoch kein ValueType und seine Standard-Hash-Funktion verwendet zumindest alle Felder. Wenn das Hauptproblem Ihres Codes jedoch Kollisionen sind, implementieren Sie eine Optimierung GetHashCode(), die Ihren Daten entspricht.
Eldritch Conundrum
1
Obwohl Tuple kein ValueType aus meinen Tests ist, leidet es unter vielen Kollisionen
Paparazzo
5
Ich denke, diese Antwort ist veraltet, da wir ValueTuples haben. Sie haben eine schönere Syntax in C # und scheinen GetHashCode doppelt so schnell zu machen wie Tuples
Lucian Wischik
3
@ LucianWischik Danke, ich habe die Antwort aktualisiert, um sie zu erwähnen.
Eldritch Conundrum
22

Der beste Weg, den ich mir vorstellen kann, besteht darin, eine CompositeKey-Struktur zu erstellen und die Methoden GetHashCode () und Equals () zu überschreiben, um Geschwindigkeit und Genauigkeit bei der Arbeit mit der Sammlung sicherzustellen:

class Program
{
    static void Main(string[] args)
    {
        DateTime firstTimestamp = DateTime.Now;
        DateTime secondTimestamp = firstTimestamp.AddDays(1);

        /* begin composite key dictionary populate */
        Dictionary<CompositeKey, string> compositeKeyDictionary = new Dictionary<CompositeKey, string>();

        CompositeKey compositeKey1 = new CompositeKey();
        compositeKey1.Int1 = 11;
        compositeKey1.Int2 = 304;
        compositeKey1.DateTime = firstTimestamp;

        compositeKeyDictionary[compositeKey1] = "FirstObject";

        CompositeKey compositeKey2 = new CompositeKey();
        compositeKey2.Int1 = 12;
        compositeKey2.Int2 = 9852;
        compositeKey2.DateTime = secondTimestamp;

        compositeKeyDictionary[compositeKey2] = "SecondObject";
        /* end composite key dictionary populate */

        /* begin composite key dictionary lookup */
        CompositeKey compositeKeyLookup1 = new CompositeKey();
        compositeKeyLookup1.Int1 = 11;
        compositeKeyLookup1.Int2 = 304;
        compositeKeyLookup1.DateTime = firstTimestamp;

        Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup1]);

        CompositeKey compositeKeyLookup2 = new CompositeKey();
        compositeKeyLookup2.Int1 = 12;
        compositeKeyLookup2.Int2 = 9852;
        compositeKeyLookup2.DateTime = secondTimestamp;

        Console.Out.WriteLine(compositeKeyDictionary[compositeKeyLookup2]);
        /* end composite key dictionary lookup */
    }

    struct CompositeKey
    {
        public int Int1 { get; set; }
        public int Int2 { get; set; }
        public DateTime DateTime { get; set; }

        public override int GetHashCode()
        {
            return Int1.GetHashCode() ^ Int2.GetHashCode() ^ DateTime.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj is CompositeKey)
            {
                CompositeKey compositeKey = (CompositeKey)obj;

                return ((this.Int1 == compositeKey.Int1) &&
                        (this.Int2 == compositeKey.Int2) &&
                        (this.DateTime == compositeKey.DateTime));
            }

            return false;
        }
    }
}

Ein MSDN-Artikel zu GetHashCode ():

http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx

Allen E. Scharfenberg
quelle
Ich glaube nicht, dass dies zu 100% sicher ist, dass es sich um einen eindeutigen Hashcode handelt, nur sehr wahrscheinlich.
Hans Olsson
Das kann sehr gut wahr sein! Laut dem verlinkten MSDN-Artikel ist dies die empfohlene Methode, um GetHashCode () zu überschreiben. Da ich in meiner täglichen Arbeit jedoch nicht viele zusammengesetzte Schlüssel verwende, kann ich nicht sicher sagen.
Allen E. Scharfenberg
4
Ja. Wenn Sie Dictionary.FindEntry () mit Reflector zerlegen, werden Sie feststellen, dass sowohl der Hashcode als auch die vollständige Gleichheit getestet werden. Der Hashcode wird zuerst getestet und schließt, falls er fehlschlägt, den Zustand kurz, ohne die vollständige Gleichheit zu überprüfen. Wenn der Hash erfolgreich ist, wird auch die Gleichheit getestet.
Jason Kleban
1
Und ja, Gleichheit sollte auch überschrieben werden, um zu passen. Selbst wenn GetHashCode () für eine Instanz 0 zurückgeben würde, würde Dictionary immer noch funktionieren, es wäre nur langsamer.
Jason Kleban
2
Der eingebaute Tupel-Typ implementiert eine Hash-Kombination als '(h1 << 5) + h1 ^ h2' anstelle von 'h1 ^ h2'. Ich denke, sie tun dies, um Kollisionen jedes Mal zu vermeiden, wenn die beiden zu hashenden Objekte gleich dem gleichen Wert sind.
Eldritch Conundrum
13

Wie wäre es mit Dictionary<int, Dictionary<int, Dictionary<DateTime, MyClass>>>?

Dies würde Ihnen Folgendes ermöglichen:

MyClass item = MyData[8][23923][date];
Jason Kleban
quelle
1
Dadurch wird viel mehr Objekt erstellt als mit einer CompositeKey-Struktur oder -Klasse. und wird auch langsamer sein, da zwei Nachschlageebenen verwendet werden.
Ian Ringrose
Ich glaube, es ist die gleiche Anzahl von Vergleichen - ich sehe nicht, wie viel mehr Objekte es geben würde - zusammengesetzte Schlüssel benötigen immer noch einen Schlüssel, und es sind Komponentenwerte oder Objekte und ein Diktat, um sie zu halten. Auf diese verschachtelte Weise benötigen Sie nicht den Wrapper-Schlüssel für jedes Objekt / jeden Wert, sondern ein zusätzliches Diktat für jede zusätzliche Verschachtelungsebene. Was denken Sie?
Jason Kleban
9
Basierend auf meinem Benchmarking, das ich mit Schlüsseln mit 2 und 3 Teilen ausprobiert habe: Eine verschachtelte Wörterbuchlösung ist 3-4x schneller als die Verwendung eines Tupel-Composite-Key-Ansatzes. Der Tupel-Ansatz ist jedoch viel einfacher / aufgeräumter.
RickL
5
@RickL Ich kann diese Benchmarks bestätigen. Wir verwenden in unserer Codebasis einen Typ namens CompositeDictionary<TKey1, TKey2, TValue>(etc), der einfach von Dictionary<TKey1, Dictionary<TKey2, TValue>>(oder wie viele verschachtelte Wörterbücher auch immer erforderlich sind ) erbt . Ohne den gesamten Typ von Grund auf selbst zu implementieren (anstatt mit zu betrügen verschachtelte Wörterbücher oder Typen, die die Schlüssel enthalten) Dies ist das schnellste, das wir bekommen.
Adam Houldsworth
1
Der Ansatz für verschachtelte Diktate sollte nur für die Hälfte (?) Der Fälle schneller sein, in denen die Daten nicht vorhanden sind, da die Zwischenwörterbücher die vollständige Berechnung und den Vergleich des Hashcodes umgehen können. Bei Vorhandensein von Daten sollte es langsamer sein, da grundlegende Vorgänge wie Hinzufügen, Enthalten usw. dreimal ausgeführt werden sollten. Ich bin mir sicher, dass die Marge mit dem Tupel-Ansatz in einigen der oben genannten Benchmarks übertroffen wird, wenn es um die Implementierungsdetails von .NET-Tupeln geht, die angesichts der Boxstrafe, die sie für Werttypen mit sich bringt, ziemlich schlecht sind. Ein richtig implementiertes Triplett ist das, was ich machen würde, wenn man auch das Gedächtnis berücksichtigt
nawfal
12

Sie können sie in einer Struktur speichern und als Schlüssel verwenden:

struct CompositeKey
{
  public int value1;
  public int value2;
  public DateTime value3;
}

Link zum Abrufen des Hash-Codes: http://msdn.microsoft.com/en-us/library/system.valuetype.gethashcode.aspx

kemiller2002
quelle
Ich stecke in .NET 3.5 fest, daher habe ich keinen Zugriff auf Tuples. Dies ist also eine gute Lösung!
Aarona
Ich bin überrascht, dass dies nicht mehr positiv bewertet wird. Es ist eine einfache Lösung, die besser lesbar ist als ein Tupel.
Mark
1
Laut msdn funktioniert dies in Ordnung, wenn keine Felder Referenztypen sind, andernfalls wird die Reflexion für die Gleichheit verwendet.
Gregor Slavec
@Mark Das Problem mit einer Struktur besteht darin, dass die standardmäßige Implementierung von GetHashCode () nicht garantiert, dass alle Felder der Struktur verwendet werden (was zu einer schlechten Wörterbuchleistung führt), während Tuple eine solche Garantie bietet. Ich habe es getestet. Weitere Informationen finden Sie unter stackoverflow.com/questions/3841602/… .
Eldritch Conundrum
8

Nachdem VS2017 / C # 7 veröffentlicht wurde, ist die beste Antwort die Verwendung von ValueTuple:

// declare:
Dictionary<(string, string, int), MyClass> index;

// populate:
foreach (var m in myClassList) {
  index[(m.Name, m.Path, m.JobId)] = m;
}

// retrieve:
var aMyClass = index[("foo", "bar", 15)];

Ich habe das Wörterbuch mit einem anonymen ValueTuple deklariert (string, string, int). Aber ich hätte ihnen Namen geben können (string name, string path, int id).

Perfekt ist das neue ValueTuple schneller als Tuple, GetHashCodeaber langsamer Equals. Ich denke, Sie müssten vollständige End-to-End-Experimente durchführen, um herauszufinden, welches für Ihr Szenario wirklich am schnellsten ist. Aber die End-to-End-Freundlichkeit und Sprachsyntax für ValueTuple macht es zu einem Gewinn.

// Perf from https://gist.github.com/ljw1004/61bc96700d0b03c17cf83dbb51437a69
//
//              Tuple ValueTuple KeyValuePair
//  Allocation:  160   100        110
//    Argument:   75    80         80    
//      Return:   75   210        210
//        Load:  160   170        320
// GetHashCode:  820   420       2700
//      Equals:  280   470       6800
Lucian Wischik
quelle
Ja, ich habe eine große Umschreibung durchlaufen, nur um die Lösung für anonyme Typen in die Luft zu jagen (ich kann keine anonymen Typen vergleichen, die mit verschiedenen Assemblys erstellt wurden). Das ValueTuple scheint eine relativ elegante Lösung für das Problem der zusammengesetzten Wörterbuchschlüssel zu sein.
Quarkly
5

Zwei Ansätze fallen mir sofort ein:

  1. Tun Sie, was Kevin vorgeschlagen hat, und schreiben Sie eine Struktur, die als Schlüssel dient. Stellen Sie sicher, dass diese Struktur implementiert IEquatable<TKey>und ihre Equalsund GetHashCodeMethoden * überschrieben werden.

  2. Schreiben Sie eine Klasse, die intern verschachtelte Wörterbücher verwendet. Etwas wie: TripleKeyDictionary<TKey1, TKey2, TKey3, TValue>... diese Klasse würde intern hat ein Mitglied des Typs Dictionary<TKey1, Dictionary<TKey2, Dictionary<TKey3, TValue>>>, und würde Methoden aus , wie zB this[TKey1 k1, TKey2 k2, TKey3 k3], ContainsKeys(TKey1 k1, TKey2 k2, TKey3 k3)usw.

* Ein Wort dazu, ob das Überschreiben der EqualsMethode erforderlich ist: Zwar Equalsvergleicht die Methode für eine Struktur standardmäßig den Wert jedes Mitglieds, verwendet jedoch die Reflexion, die von Natur aus Leistungskosten verursacht, und ist daher nicht sehr wichtig angemessene Implementierung für etwas, das als Schlüssel in einem Wörterbuch verwendet werden soll (meiner Meinung nach jedenfalls). Gemäß der MSDN-Dokumentation zu ValueType.Equals:

Die Standardimplementierung der Equals-Methode verwendet Reflection, um die entsprechenden Felder von obj und dieser Instanz zu vergleichen. Überschreiben Sie die Equals-Methode für einen bestimmten Typ, um die Leistung der Methode zu verbessern und das Konzept der Gleichheit für den Typ genauer darzustellen.

Dan Tao
quelle
In Bezug auf 1 glaube ich nicht, dass Sie Equals und GetHashcode überschreiben müssen. Die Standardimplementierung von Equals überprüft automatisch alle Felder auf Gleichheit, von denen ich denke, dass sie in dieser Struktur in Ordnung sein sollten.
Hans Olsson
@ho: Es ist möglicherweise nicht notwendig , aber ich würde dringend empfehlen, dies für jede Struktur zu tun, die als Schlüssel dienen wird. Siehe meine Bearbeitung.
Dan Tao
3

Wenn der Schlüssel Teil der Klasse ist, verwenden Sie KeyedCollection.
Hier wird Dictionaryder Schlüssel vom Objekt abgeleitet.
Unter der Decke ist es Wörterbuch.
Sie müssen den Schlüssel im Keyund nicht wiederholen Value.
Warum ein Risiko eingehen, ist der Schlüssel nicht der gleiche Keywie der Value.
Sie müssen nicht dieselben Informationen im Speicher duplizieren.

KeyedCollection-Klasse

Indexer, um den zusammengesetzten Schlüssel verfügbar zu machen

    using System.Collections.ObjectModel;

    namespace IntIntKeyedCollection
    {
        class Program
        {
            static void Main(string[] args)
            {
                Int32Int32DateO iid1 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
                Int32Int32DateO iid2 = new Int32Int32DateO(0, 1, new DateTime(2007, 6, 1, 8, 30, 52));
                if (iid1 == iid2) Console.WriteLine("same");
                if (iid1.Equals(iid2)) Console.WriteLine("equals");
                // that are equal but not the same I don't override = so I have both features

                Int32Int32DateCollection int32Int32DateCollection = new Int32Int32DateCollection();
                // dont't have to repeat the key like Dictionary
                int32Int32DateCollection.Add(new Int32Int32DateO(0, 0, new DateTime(2008, 5, 1, 8, 30, 52)));
                int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
                int32Int32DateCollection.Add(iid1);
                //this would thow a duplicate key error
                //int32Int32DateCollection.Add(iid2);
                //this would thow a duplicate key error
                //int32Int32DateCollection.Add(new Int32Int32DateO(0, 1, new DateTime(2008, 6, 1, 8, 30, 52)));
                Console.WriteLine("count");
                Console.WriteLine(int32Int32DateCollection.Count.ToString());
                // reference by ordinal postion (note the is not the long key)
                Console.WriteLine("oridinal");
                Console.WriteLine(int32Int32DateCollection[0].GetHashCode().ToString());
                // reference by index
                Console.WriteLine("index");
                Console.WriteLine(int32Int32DateCollection[0, 1, new DateTime(2008, 6, 1, 8, 30, 52)].GetHashCode().ToString());
                Console.WriteLine("foreach");
                foreach (Int32Int32DateO iio in int32Int32DateCollection)
                {
                    Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
                }
                Console.WriteLine("sorted by date");
                foreach (Int32Int32DateO iio in int32Int32DateCollection.OrderBy(x => x.Date1).ThenBy(x => x.Int1).ThenBy(x => x.Int2))
                {
                    Console.WriteLine(string.Format("HashCode {0} Int1 {1} Int2 {2} DateTime {3}", iio.GetHashCode(), iio.Int1, iio.Int2, iio.Date1));
                }
                Console.ReadLine();
            }
            public class Int32Int32DateCollection : KeyedCollection<Int32Int32DateS, Int32Int32DateO>
            {
                // This parameterless constructor calls the base class constructor 
                // that specifies a dictionary threshold of 0, so that the internal 
                // dictionary is created as soon as an item is added to the  
                // collection. 
                // 
                public Int32Int32DateCollection() : base(null, 0) { }

                // This is the only method that absolutely must be overridden, 
                // because without it the KeyedCollection cannot extract the 
                // keys from the items.  
                // 
                protected override Int32Int32DateS GetKeyForItem(Int32Int32DateO item)
                {
                    // In this example, the key is the part number. 
                    return item.Int32Int32Date;
                }

                //  indexer 
                public Int32Int32DateO this[Int32 Int1, Int32 Int2, DateTime Date1]
                {
                    get { return this[new Int32Int32DateS(Int1, Int2, Date1)]; }
                }
            }

            public struct Int32Int32DateS
            {   // required as KeyCollection Key must be a single item
                // but you don't really need to interact with Int32Int32DateS directly
                public readonly Int32 Int1, Int2;
                public readonly DateTime Date1;
                public Int32Int32DateS(Int32 int1, Int32 int2, DateTime date1)
                { this.Int1 = int1; this.Int2 = int2; this.Date1 = date1; }
            }
            public class Int32Int32DateO : Object
            {
                // implement other properties
                public Int32Int32DateS Int32Int32Date { get; private set; }
                public Int32 Int1 { get { return Int32Int32Date.Int1; } }
                public Int32 Int2 { get { return Int32Int32Date.Int2; } }
                public DateTime Date1 { get { return Int32Int32Date.Date1; } }

                public override bool Equals(Object obj)
                {
                    //Check for null and compare run-time types.
                    if (obj == null || !(obj is Int32Int32DateO)) return false;
                    Int32Int32DateO item = (Int32Int32DateO)obj;
                    return (this.Int32Int32Date.Int1 == item.Int32Int32Date.Int1 &&
                            this.Int32Int32Date.Int2 == item.Int32Int32Date.Int2 &&
                            this.Int32Int32Date.Date1 == item.Int32Int32Date.Date1);
                }
                public override int GetHashCode()
                {
                    return (((Int64)Int32Int32Date.Int1 << 32) + Int32Int32Date.Int2).GetHashCode() ^ Int32Int32Date.GetHashCode();
                }
                public Int32Int32DateO(Int32 Int1, Int32 Int2, DateTime Date1)
                {
                    Int32Int32DateS int32Int32Date = new Int32Int32DateS(Int1, Int2, Date1);
                    this.Int32Int32Date = int32Int32Date;
                }
            }
        }
    }

Für die Verwendung des Werttyps fpr empfiehlt der Schlüssel, den Microsoft ausdrücklich empfiehlt.

ValueType.GetHashCode

Tuple ist technisch gesehen kein Werttyp, leidet jedoch unter demselben Symptom (Hash-Kollisionen) und ist kein guter Kandidat für einen Schlüssel.

Paparazzo
quelle
+1 für eine korrektere Antwort. Überrascht erwähnte es niemand früher. Abhängig davon, wie OP die Struktur verwenden möchte, wäre HashSet<T>eine entsprechende IEqualityComparer<T>Option ebenfalls möglich. Übrigens, ich denke, Ihre Antwort wird Stimmen anziehen, wenn Sie Ihre Klassennamen und andere Mitgliedsnamen ändern können :)
Nawfal
2

Darf ich eine Alternative vorschlagen - ein anonymes Objekt. Es ist dasselbe, das wir in der GroupBy LINQ-Methode mit mehreren Schlüsseln verwenden.

var dictionary = new Dictionary<object, string> ();
dictionary[new { a = 1, b = 2 }] = "value";

Es mag seltsam aussehen, aber ich habe Tuple.GetHashCode und neue {a = 1, b = 2} .GetHashCode-Methoden verglichen und die anonymen Objekte gewinnen auf meinem Computer unter .NET 4.5.1:

Objekt - 89.1732 ms für 10000 Anrufe in 1000 Zyklen

Tupel - 738.4475 ms für 10000 Anrufe in 1000 Zyklen

Michael Logutov
quelle
omg, diese Alternative war mir nie in den Sinn gekommen ... Ich weiß nicht, ob sie sich gut verhält, wenn Sie einen komplexen Typ als zusammengesetzten Schlüssel verwenden.
Gabriel Espinoza
Wenn Sie einfach ein Objekt übergeben (anstelle eines anonymen), wird das Ergebnis der GetHashCode-Methode dieses Objekts verwendet. Wenn Sie es wie dictionary[new { a = my_obj, b = 2 }]folgt verwenden, ist der resultierende Hash-Code eine Kombination aus my_obj.GetHashCode und ((Int32) 2) .GetHashCode.
Michael Logutov
VERWENDEN SIE DIESE METHODE NICHT! Unterschiedliche Assemblys erstellen unterschiedliche Namen für anonyme Typen. Während es für Sie anonym aussieht, wird hinter den Kulissen eine konkrete Klasse erstellt und zwei Objekte aus zwei verschiedenen Klassen sind nicht gleich dem Standardoperator.
Quarkly
Und wie ist das in diesem Fall wichtig?
Michael Logutov
0

Eine andere Lösung für die bereits erwähnten wäre, eine Art Liste aller bisher generierten Schlüssel zu speichern. Wenn ein neues Objekt generiert wird, generieren Sie dessen Hashcode (nur als Ausgangspunkt). Überprüfen Sie, ob es bereits in der Liste enthalten ist Fügen Sie dann einen zufälligen Wert usw. hinzu, bis Sie einen eindeutigen Schlüssel haben. Speichern Sie diesen Schlüssel dann im Objekt selbst und in der Liste und geben Sie ihn jederzeit als Schlüssel zurück.

Hans Olsson
quelle