Der angegebene Schlüssel war im Wörterbuch nicht vorhanden. Welcher Schlüssel?

76

Gibt es eine Möglichkeit, den Wert des angegebenen Schlüssels in der folgenden Ausnahme in C # so abzurufen, dass alle generischen Klassen betroffen sind? Ich denke, dies ist ein großer Fehler in der Ausnahmebeschreibung von Microsoft.

"The given key was not present in the dictionary."

Ein besserer Weg wäre:

"The given key '" + key.ToString() + "' was not present in the dictionary."

Lösungen können Mixins oder abgeleitete Klassen beinhalten.

Andreas
quelle
13
Diese Frage scheint nicht zum Thema zu gehören, da es sich um die Implementierung einer Ausnahmemeldung und nicht um eine Programmierfrage handelt.
Servy
6
Problem hierbei ist, dass der Debugger nicht immer verfügbar ist, beispielsweise beim Lesen der Protokolldatei.
Andreas
4
Sie gehen davon aus, dass alle Wörterbücher einen Schlüssel haben, .ToString()der Sinn macht. Ich stimme im Fall von a zu, Dictionary<string, *>dass es eine nette Ergänzung zur Ausnahmebeschreibung wäre, aber es kann nicht auf alle Arten von Dictionary<*,*>Objekten angewendet werden.
Demoncodemonkey
2
Nein, aber selbst wenn der Schlüssel.ToString () manchmal "Objekt" sagen würde, würde es in vielleicht 90% der Fälle immer noch funktionieren.
Andreas
3
Ich denke, ein Grund dafür ist, dass MS absolut keine Ahnung hat, was der Schlüssel ist oder ob er freigelegt werden sollte. Es kann sich um PII oder ein Geheimnis handeln, das nicht protokolliert werden sollte. Das sicherere Verhalten besteht darin, weniger Details offenzulegen, wenn Sie nicht wissen, wer sie sehen wird.
Mike Zboray

Antworten:

70

Diese Ausnahme wird ausgelöst, wenn Sie versuchen, auf etwas zu indizieren, das nicht vorhanden ist. Beispiel:

Dictionary<String, String> test = new Dictionary<String,String>();
test.Add("Key1,"Value1");
string error = test["Key2"];

Oft ist so etwas wie ein Objekt der Schlüssel, was es zweifellos schwieriger macht, es zu bekommen. Sie können jedoch immer Folgendes schreiben (oder es sogar in eine Erweiterungsmethode einschließen):

if (test.ContainsKey(myKey))
   return test[myKey];
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Oder effizienter (dank @ScottChamberlain)

T retValue;
if (test.TryGetValue(myKey, out retValue))
    return retValue;
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Microsoft hat dies nicht getan, wahrscheinlich weil es bei den meisten Objekten nutzlos wäre. Es ist einfach genug, um es selbst zu tun, also rollen Sie einfach Ihre eigenen!

BradleyDotNET
quelle
18
Wenn Sie dies tun, führt ContainsKeyder Indexer zu zwei Suchvorgängen im Wörterbuch. Ein tun TryGetValuewürde nur eine Lookup und Sie können nur die Boolesche Ausgang benutzen , um Ihre if / else Block zu wählen.
Scott Chamberlain
1
@ ScottChamberlain Sehr wahr. Als zusätzliche Implementierung hinzugefügt.
BradleyDotNET
Versuchen Sie test.keys.contains (Schlüssel), der einen Booleschen Wert zurückgibt.
Kurkula
17

Im allgemeinen Fall lautet die Antwort Nein.

Sie können den Debugger jedoch so einstellen, dass er an dem Punkt unterbrochen wird, an dem die Ausnahme zum ersten Mal ausgelöst wird. Zu diesem Zeitpunkt ist der Schlüssel, der nicht vorhanden war, als Wert im Aufrufstapel verfügbar.

In Visual Studio befindet sich diese Option hier:

Debug → Ausnahmen ... → Common Language Runtime Exceptions → System.Collections.Generic

Dort können Sie das Kontrollkästchen " Geworfen " aktivieren .


Für spezifischere Fälle, in denen Informationen zur Laufzeit benötigt werden, sofern Ihr Code verwendet IDictionary<TKey, TValue>und nicht direkt daran gebunden ist Dictionary<TKey, TValue>, können Sie Ihre eigene Wörterbuchklasse implementieren, die dieses Verhalten bereitstellt.

Sam Harwell
quelle
So starte ich normalerweise meinen Debugger.
AaronLS
Hallo @Sam, an welcher Stelle im Aufrufstapel finden Sie diesen Wert?
user919426
2
VS 2017 (v15.5.7) hat es wie folgt: Debug -> Windows -> Ausnahmeeinstellungen -> dann überprüfen Sie System.Collections.Generic.KeyNotFoundException
Robert Koch
9

Wenn Sie wichtige Fehler verwalten möchten, sollten Sie TryGetValue verwenden

https://msdn.microsoft.com/en-gb/library/bb347013(v=vs.110).aspx

string value = "";
if (openWith.TryGetValue("tif", out value))
{
    Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
    Console.WriteLine("Key = \"tif\" is not found.");
}
gabba
quelle
1
Dies setzt voraus, dass der Schlüssel voraussichtlich nicht vorhanden ist. Das ist möglicherweise nicht der Fall. Dies kann zu Recht ein Ausnahmefall sein.
Servy
1
string Value = dic.ContainsKey("Name") ? dic["Name"] : "Required Name"

Mit diesem Code erhalten wir String-Daten in 'Value'. Wenn der Schlüssel 'Name' im Wörterbuch 'dic' vorhanden ist, rufen Sie diesen Wert ab, andernfalls wird die Zeichenfolge "Erforderlicher Name" zurückgegeben.

Sharon AS
quelle
2
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Adiga
0

Sie können diesen Code ausprobieren

Dictionary<string,string> AllFields = new Dictionary<string,string>();  
string value = (AllFields.TryGetValue(key, out index) ? AllFields[key] : null);

Wenn der Schlüssel nicht vorhanden ist, wird einfach ein Nullwert zurückgegeben.

Nitika Chopra
quelle