The given key was not present in the dictionary. Which key?

C#ExceptionGenericsDictionary

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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!

Solution 2 - C#

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.

Solution 3 - C#

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.");
}

Solution 4 - C#

If anyone still cares in 2021 and can afford to move to .NET Core, .Net 5 finally tells us the name of the offending key:

class Program
{
	static void Main(string[] args)
	{
		Dictionary<string, object> dictionary = new()
		{
			["foo"] = new object()
		};
		Console.WriteLine(dictionary["bar"]);
	}
}

Will give you:

Unhandled exception. System.Collections.Generic.KeyNotFoundException: The given key 'bar' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at KnfTest.Program.Main(String[] args)

The same code in .Net Framework 4.8 gives the old dreaded message.

As for those who can't afford moving to Core yet I'm afraid there is no real working solution. Replacing all indexer invocations with TryGetValue is cumbersome -not to say absurd. Subclassing from Dictionary is practically impossible. Yes you can declare a new indexer but then polymorphism goes out the window as your indexer will be called only when using a reference of the subclass. Finally, creating your own Dictionary wrapper might be a solution but that's again a non trivial process, especially if you want to replicate exactly the Dictionary which implements not only IDictionary<TKey,TValue> but also:

System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>
System.Collections.IDictionary
System.Runtime.Serialization.IDeserializationCallback
System.Runtime.Serialization.ISerializable

Quite an overkill "just" for an exception message.

Solution 5 - C#

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.

Solution 6 - C#

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.

Solution 7 - C#

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.");
	}
}

Solution 8 - C#

In C# 7.0 or greater, you can Use the out parameter modifer to solve your problem in one line, and only make one call to the indexer. It works in c# 7.0 or greater.

public TItem GetOrException<TKey,TItem>(TKey key) where TKey : IFormattable => 
    dictionary.TryGetValue(key, out var item) ? item : throw new KeyNotFoundException( "Key: " + key.ToString() );

You can also opt for the longer try catch block which gives better exception information:

public TItem GetOrException<TKey,TItem>(TKey key) where TKey : IFormattable {
    try{ return dictionary[key]; }
    catch (KeyNotFoundException e) { throw new KeyNotFoundException("Key:" + key.ToString(), e);}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndreasView Question on Stackoverflow
Solution 1 - C#BradleyDotNETView Answer on Stackoverflow
Solution 2 - C#Sam HarwellView Answer on Stackoverflow
Solution 3 - C#gabbaView Answer on Stackoverflow
Solution 4 - C#Stelios AdamantidisView Answer on Stackoverflow
Solution 5 - C#Sharon ASView Answer on Stackoverflow
Solution 6 - C#Nitika ChopraView Answer on Stackoverflow
Solution 7 - C#Rohim ChouView Answer on Stackoverflow
Solution 8 - C#GregView Answer on Stackoverflow