2009-07-21 7 views
10

Sollte ich überprüfen, ob ein bestimmter Schlüssel in Wörterbuch vorhanden ist, wenn ich sicher bin, dass es im Wörterbuch hinzugefügt wird, bis ich den Code erreiche, um darauf zuzugreifen?Sollte ich vor dem Zugriff prüfen, ob ein bestimmter Schlüssel im Wörterbuch vorhanden ist?

Es gibt zwei Möglichkeiten, wie ich den Wert im Wörterbuch zugreifen kann

  1. Überprüfung ContainsKey Methode. Wenn es wahr zurückgibt, dann greife ich auf Indexer [Schlüssel] des Wörterbuchobjekts zu.

oder

  1. TryGetValue, die wahr oder falsch sowie Rückgabewert durch out-Parameter zurück.

(2. wird als erstes eine bessere Leistung, wenn ich Wert erhalten möchten. Benchmark.)

Allerdings, wenn ich sicher bin, dass die Funktion, die sicherlich den Schlüssel wird die globale Wörterbuch zugreift dann sollte ich noch überprüfen mit TryGetValue oder ohne Überprüfung sollte ich den Indexer [] verwenden.

Oder sollte ich das nie annehmen und immer überprüfen?

Antwort

18

Verwenden Sie den Indexer, wenn der Schlüssel vorhanden sein soll - wenn er nicht vorhanden ist, wird eine entsprechende Ausnahme ausgelöst, was das richtige Verhalten ist, wenn die Abwesenheit des Schlüssels einen Fehler anzeigt.

Wenn es gilt, dass der Schlüssel nicht vorhanden ist, verwenden Sie stattdessen TryGetValue und reagieren Sie entsprechend.

(gilt auch Marcs Beratung über ein gemeinsames Wörterbuch sicher erreichbar.)

+1

Ein fehlender Schlüssel ist oft ein Hinweis auf ein anderes Problem. Wenn Sie wissen, was das Problem ist und eine nützlichere Nachricht bereitstellen können, sollten Sie in Betracht ziehen, eine eigene Ausnahme auszulösen, da die Nachricht, die 'KeyNotFoundException" begleitet, manchmal schwierig einzugrenzen ist. –

+0

Es wäre sicherlich nützlich, wenn KeyNotFoundException den Schlüssel auch gab - aber ansonsten reicht mir normalerweise nur der Stack-Trace. Wie weit würdest du das nehmen: jede mögliche NULL-Referenz (nicht nur Argumente, sondern Dinge, von denen du erwartest, dass sie nicht null sind) auf Nichtigkeit prüfen und eine eigene Ausnahme auf jede davon werfen? Bei internen Inkonsistenzen gibt es immer Ausnahmen, die von Teilen des Frameworks ausgelöst werden: Wenn Sie versuchen, jeden einzelnen davon zu antizipieren, geht der Code mehr über die Fehlerfälle als über Fortschritte. –

10

Wenn das Wörterbuch global (statisch/gemeinsam) ist, sollten Sie den Zugriff darauf synchronisieren (dies ist wichtig; andernfalls können Sie es korrumpieren).

Auch wenn Ihr Thread nur lesen Daten ist, muss es die Sperren anderer Threads respektieren, die es möglicherweise bearbeiten.

Jedoch; wenn Sie sicher sind, dass das Element ist, sollte der Indexer in Ordnung sein:

Foo foo; 
lock(syncLock) { 
    foo = data[key]; 
} 
// use foo... 

Ansonsten ein nützliches Muster in der gleichen Sperre zu überprüfen und fügen ist:

Foo foo; 
lock(syncLock) { 
    if(!data.TryGetValue(key, out foo)) { 
     foo = new Foo(key); 
     data.Add(key, foo); 
    } 
} 
// use foo... 

hier nur fügen wir die Artikel, wenn es nicht da war ... aber innerhalb des gleichen Schlosses.

+0

Schön, aber ich denke nicht, dass das die Frage war? Ich sehe keinen Hinweis auf Nebenläufigkeit? :) – Thorarin

+0

"globales Wörterbuch" - setze mich einfach auf einen bestimmten Pfad. Wenn mein Verständnis falsch ist, kann das OP diese Antwort einfach ignorieren; -p –

+0

Warum müssen wir beim Lesen von Daten aus dem Wörterbuch die Sperre übernehmen? Liegt es an der Wörterbuch-Erweiterung/dem Re-Hashing nach einer gewissen Grenze? –

2

Immer überprüfen. Sag niemals nie. Ich gehe davon aus, dass Ihre Anwendung nicht so leistungsfähig ist, dass Sie die Prüfzeit speichern müssen.

TIPP: Wenn Sie nicht überprüfen wollen, verwenden Sie mindestens Debug.Assert (dict.ContainsKey (key)); Dies wird nur im Debug-Modus kompiliert, dein Build enthält es nicht. So könnte man beim Debuggen zumindest die Kontrolle haben.

Still: Wenn möglich, überprüfen Sie es einfach :-)

EDIT: Es gab hier einige Missverständnisse. Mit "immer prüfen" meinte ich nicht nur ein if irgendwo. Eine korrekte Behandlung einer Ausnahme wurde ebenfalls berücksichtigt. Also, um genauer zu sein: Niemals etwas für selbstverständlich halten, das Unerwartete erwarten. Überprüfen Sie mit ContainsKey oder behandeln Sie die potenzielle Ausnahme, aber tun Sie ETWAS, falls das Element nicht enthalten ist.

+4

Dem widerspreche ich. Wenn der Schlüssel vorhanden sein soll und nicht ist, ist das richtige Verhalten, eine Ausnahme zu werfen, ja? Und genau das macht der Indexer - warum also nicht dieses Verhalten? Außerdem bin ich nicht scharf darauf, das Verhalten zwischen Debug- und Release-Builds zu ändern ... es klingt wie ein Rezept für Probleme für mich. –

+0

Ja, die Debug-Überprüfung war nicht als bewährte Methode gedacht. Aber es ist besser als überhaupt nicht zu überprüfen. Und eine Ausnahme auszulösen, wenn die Daten im Dictionary sein sollten, ist der richtige Weg, aber dann ist es wahrscheinlich keine interne Ausnahme von Dictionary, sondern eine, die besser zum tatsächlichen Problem passt (z. B. InvalidOperationException). – galaktor

+0

Ich stimme Jon zu, Sie überprüfen nur, ob es da ist oder nicht, wenn Sie sicher sind, dass es da sein sollte, dann ist der richtige Weg, die Ausnahme auszulösen und entsprechend zu behandeln. – James

0

TryGetValue ist den gleichen Code wie es durch Schlüssel indizieren, mit Ausnahme der früheren Renditen einen Standardwert (für den out Parameter), wobei letztere ein wirft Ausnahme. Verwenden Sie TryGetValue und Sie erhalten konsistente Überprüfungen mit absolut keinem Leistungsverlust.

Bearbeiten: Wie Jon sagte, wenn Sie wissen, dass es immer den Schlüssel haben wird, dann können Sie es indizieren und lassen Sie es die entsprechende Ausnahme werfen. Wenn Sie jedoch bessere Kontextinformationen bereitstellen können, indem Sie sie selbst mit einer detaillierten Nachricht versehen, wäre dies vorzuziehen.

0

Es gibt 2 Gedankengänge aus Sicht der Leistung.

1) Vermeiden Sie Ausnahmen, wo dies möglich ist, da Ausnahmen teuer sind - d. H. Überprüfen Sie, bevor Sie versuchen, einen bestimmten Schlüssel aus dem Wörterbuch abzurufen, ob vorhanden oder nicht. Meiner Meinung nach besser, wenn es eine faire Chance gibt, die es möglicherweise nicht gibt. Dies würde ziemlich häufige Ausnahmen verhindern.

2) Wenn Sie sicher sind, dass das Objekt in 99% der Zeit existiert, dann prüfen Sie nicht, ob es existiert, bevor Sie darauf zugreifen. Die 1% der Zeiten, wenn es nicht existiert, wird eine Ausnahme geworfen, aber Sie haben Zeit für die anderen 99% der Zeit gespeichert, indem Sie nicht überprüft haben.

Was ich sage ist, optimieren für die Mehrheit, wenn es eine klare ist. Wenn es einen echten Grad an Ungewissheit über einen vorhandenen Gegenstand gibt, überprüfen Sie vor dem Abrufen.

+0

Ich denke nicht, dass es wirklich um Leistung geht. Es sollte sich um Korrektheit handeln: Wenn der Schlüssel * erwartet * in korrekten Situationen da ist, d. H. Es ist ein Fehler für den Schlüssel, nicht da zu sein, dann ist das Auslösen einer Ausnahme der richtige Ansatz zum Scheitern. Andernfalls sollten Sie diese Situation * ohne * mit einer Ausnahme erkennen - die Behandlung von Ausnahmefällen mit Ausnahmen ist eine schlechte Idee, IMO. –

+0

Ich denke mehr aus dem Szenario, wo es nicht im Wörterbuch sollte nicht zu einem Fehler z. sollte stattdessen einen Standardwert verwenden, oder sollte es hinzufügen, wenn es nicht existiert. Der Fall, in dem es im Wörterbuch vorhanden sein sollte, aber es ist kein echter Fehler, wenn es nicht existiert - dh das Wörterbuch ist ein Cache einiger Daten aus einer DB, sagen wir, die DB ist nicht verfügbar und der Cache wird nicht gefüllt, aber das soll nicht zu einem Fehler im System führen. Es ist schwierig, ein realistisches Beispiel zu finden, also hoffe, dass ich einen Sinn habe! – AdaTheDev

0

Wenn Sie wissen, dass das Wörterbuch normalerweise den Schlüssel enthält, müssen Sie vor dem Zugriff nicht darauf achten.

Wenn etwas nicht stimmt und das Wörterbuch nicht die Elemente enthält, die es enthalten soll, können Sie das Wörterbuch die Ausnahme auslösen lassen. Der einzige Grund, zuerst nach dem Schlüssel zu suchen, wäre, wenn Sie sich selbst um dieses Problem kümmern möchten, ohne die Ausnahme zu bekommen. Wenn das Wörterbuch die Ausnahme auslöst und abfängt, ist dies jedoch ein vollkommen gültiger Weg, um mit der Situation umzugehen.

0

Ich denke Marc und Jon haben es (wie immer) schön ausgesät. Da Sie in Ihrer Frage auch die Leistung erwähnen, könnte es sich lohnen, darüber nachzudenken, wie Sie das Wörterbuch sperren.

Die einfache lock serialisiert alle Lesezugriffe, die nicht wünschenswert sind, wenn das Lesen sehr häufig ist und Schreibvorgänge relativ selten sind. In diesem Fall könnte ein ReaderWriterLockSlim besser sein. Der Nachteil ist, dass der Code etwas komplexer ist und die Schreibvorgänge etwas langsamer sind.

1

Persönlich würde ich überprüfen, der Schlüssel ist da, unabhängig davon, ob Sie sicher sind oder nicht, einige sagen, diese Überprüfung ist überflüssig und das Wörterbuch wird eine Ausnahme werfen, die Sie fangen können, aber ich sollte Sie nicht verlassen Bei dieser Ausnahme sollten Sie sich selbst überprüfen und dann entweder Ihre eigene Exception werfen, was etwas bedeutet, oder ein Ergebnisobjekt mit einer Erfolgsmarkierung und einem Grund innerhalb ... der Fehlermechanismus ist wirklich implementierungsabhängig.

1

Sicher ist die Antwort "es hängt alles von der Situation ab".Sie müssen das Risiko abwägen, dass der Schlüssel im Wörterbuch fehlt (gering für kleine Systeme mit beschränktem Zugriff auf die Daten, wo Sie sich auf die Reihenfolge der Dinge verlassen können, größer für größere Systeme, mehrere Programmierer greifen auf dieselben zu) Daten, insbesondere mit Lese-/Schreib-/Löschzugriff, bei denen Threads involviert sind und die Reihenfolge nicht garantiert werden kann oder wo Daten extern entstehen und das Lesen scheitern kann) mit der Auswirkung des Risikos (sicherheitskritische Systeme, kommerzielle Releases oder Systeme, die ein Unternehmen benötigt) Verlass im Vergleich mit etwas, das zum Spaß gemacht wurde, für eine einmalige Arbeit und/oder nur für Ihren Gebrauch) und mit allen Anforderungen an Geschwindigkeit, Größe und Faulheit.

Wenn ich ein System zur Kontrolle der Eisenbahnsignalisierung machen würde, wäre ich sicher vor allen möglichen und unmöglichen Fehlern und sicher vor Fehlern in der Fehlerbehandlung und so weiter (Murphys 2. Gesetz: "Was nicht gehen kann falsch wird schief gehen ".) Wenn ich Sachen zum Spaß zusammen schmeiße, auch wenn Größe und Geschwindigkeit kein Thema sind, werde ich viel entspannter über solche Sachen sein - ich werde zu den lustigen Sachen kommen wollen.

Natürlich ist das manchmal der Spaß an sich.

Verwandte Themen