Ich gehe davon aus, dass Sie ContainsKey
statt Contains
schreiben soll. Contains
auf einem Dictionary
ist explizit implementiert, so dass es nicht über den Typ zugänglich ist, den Sie deklariert haben.
Ihr Code ist nicht sicher. Der Grund dafür ist, dass nichts verhindert ContainsKey
und Add
zur gleichen Zeit ausgeführt werden kann. Es gibt tatsächlich einige ziemlich bemerkenswerte Fehlerszenarien, die dies einführen würde. Da ich gesehen habe, wie die Dictionary
implementiert ist, kann ich sehen, dass Ihr Code eine Situation verursachen könnte, in der Datenstruktur Duplikate enthält. Und ich meine es wörtlich enthält Duplikate. Die Ausnahme wird nicht unbedingt ausgelöst. Die anderen Misserfolgszenarien werden immer seltsamer und seltsamer, aber ich werde hier nicht näher darauf eingehen.
Eine geringfügige Änderung an Ihrem Code könnte eine Variation des doppelt überprüften Sperrmusters beinhalten.
public void MyMethod(string a)
{
if (!dictionary.ContainsKey(a))
{
lock (dictionary)
{
if (!dictionary.ContainsKey(a))
{
dictionary.Add(a, "someothervalue");
}
}
}
}
Dies ist natürlich nicht sicherer aus dem Grund, den ich bereits angegeben habe. Tatsächlich ist es schwierig, das doppelt überprüfte Sperrmuster in allen, außer den einfachsten Fällen (wie die kanonische Implementierung eines Singleton), zu korrigieren. Zu diesem Thema gibt es viele Variationen. Sie können es mit TryGetValue
oder dem Standard-Indexer versuchen, aber letztendlich sind alle diese Variationen einfach falsch.
Also wie könnte das richtig gemacht werden, ohne ein Schloss zu nehmen? Sie könnten versuchen ConcurrentDictionary
. Es hat die Methode GetOrAdd
, die in diesen Szenarien wirklich nützlich ist. Ihr Code würde so aussehen.
public void MyMethod(string a)
{
// The variable 'dictionary' is a ConcurrentDictionary.
dictionary.GetOrAdd(a, "someothervalue");
}
Das ist alles, was es ist. Die GetOrAdd
Funktion überprüft, ob das Element vorhanden ist. Wenn nicht, wird es hinzugefügt. Andernfalls wird die Datenstruktur in Ruhe gelassen. Dies alles geschieht auf thread-sichere Weise. In den meisten Fällen macht das ConcurrentDictionary
dies, ohne auf ein Schloss zu warten. 2
By the way, Ihr Variablenname ist zu widerlich. Wenn es nicht für Servys Kommentar gewesen wäre, hätte ich vielleicht die Tatsache übersehen, dass wir über eine Dictionary
im Gegensatz zu einer List
sprachen. In der Tat, basierend auf dem Contains
Anruf dachte ich zuerst, wir sprachen über eine List
.
Auf den ConcurrentDictionary
Leser sind völlig frei sperren. Writer immer nehmen Sie eine Sperre (fügt hinzu und aktualisiert das ist; die Entfernung ist noch frei von Sperren). Dies beinhaltet die GetOrAdd
Funktion. Der Unterschied besteht darin, dass die Datenstruktur mehrere mögliche Sperroptionen enthält, sodass in den meisten Fällen keine oder nur geringe Sperrkonflikte auftreten. Aus diesem Grund wird diese Datenstruktur als "Low Lock" oder "Concurrent" im Gegensatz zu "Lock Free" bezeichnet.
Das Aufrufen eines Wörterbuchs "Liste" ist wirklich gemein. Es entsteht der Eindruck, dass es sich eher um eine Liste als um ein Wörterbuch handelt. – Servy
@Servy Ich nannte meinen Hund "Katze" obwohl. War das auch gemein? – Cruncher
@Cruncher Nein, weil Katzen großartig sind. – Servy