91
votes

Is there a way to get the value of the given key in the following exception in C# in a way that affects all generic classes? I think this is a big miss in the exception description from Microsoft.

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

A better way would be:

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

Solutions might involve mixins or derived classes maybe.

6
This question appears to be off-topic because it is a rant about the implementation of an exception message, and not a programming question.Servy
Problem here is that the debugger is not always available, for example when reading log file.Andreas
You are assuming that all dictionaries have a key where .ToString() makes sense. I agree in the case of a Dictionary<string, *> that it would be a nice addition to the exception description, but it cannot be applied to all types of Dictionary<*,*> objects.demoncodemonkey
I think one reason it is not in there is that MS has absolutely no idea what the key is or whether it should be exposed. It could be PII or a secret that should not be logged. The safer behavior is to expose less details when you don't know who is going to see them.Mike Zboray
Agreed: this is incredibly irritating. Even the type name would be more helpful for situations where the exception is thrown in a release build and the stack trace doesn't make it obvious which line of source code the problem occurred on. I despise uninformative exception messages, and I don't find the PII argument particularly compelling. Could be sidestepped with a runtime flag, and these messages shouldn't bubble to clients in any case.Bart Read

6 Answers

81
votes

This exception is thrown when you try to index to something that isn't there, for example:

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

Often times, something like an object will be the key, which undoubtedly makes it harder to get. However, you can always write the following (or even wrap it up in an extension method):

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

Or more efficient (thanks to @ScottChamberlain)

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

Microsoft chose not to do this, probably because it would be useless when used on most objects. Its simple enough to do yourself, so just roll your own!

19
votes

In the general case, the answer is No.

However, you can set the debugger to break at the point where the exception is first thrown. At that time, the key which was not present will be accessible as a value in the call stack.

In Visual Studio, this option is located here:

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

There, you can check the Thrown box.


For more specific instances where information is needed at runtime, provided your code uses IDictionary<TKey, TValue> and not tied directly to Dictionary<TKey, TValue>, you can implement your own dictionary class which provides this behavior.

10
votes

If you want to manage key misses you should use TryGetValue

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.");
}
1
votes
string Value = dic.ContainsKey("Name") ? dic["Name"] : "Required Name"

With this code, we will get string data in 'Value'. If key 'Name' exists in the dictionary 'dic' then fetch this value, else returns "Required Name" string.

0
votes

You can try this code

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

If the key is not present, it simply returns a null value.

0
votes

Borrowed from @BradleyDotNET's anwser, here's the extension method version:

public static TValue GetValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) 
{
    if (dictionary.TryGetValue(key, out TValue result)) 
    {
        return result;
    } 
    else 
    {
        throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary.");
    }
}