Why is there no key specified with .NET KeyNotFoundException (in message/property)? Is it because of performance reasons? Is it because when Dictionary finds out there isnt any requested object by the hash it already doesnt know the context of the original key? I couldnt find an answer to this question anywhere.
-
1From a more-general, non-C#, non-.Net perspective, the assumption would be that if you intend to catch the exception and do anything about it, you've still got access to whatever key caused it to be thrown in the first place. The fact that you're querying a dictionary with a key is an implementation detail, and if your intent is to throw an exception because of bad user input, you should probably be throwing a different exception with the name of the key baked into its message. – Blrfl Apr 13 '17 at 10:54
2 Answers
This may not be the official answer, but...
C# and VB.NET - the main .NET languages - are statically typed languages(yea, I know, they support dynamic typing, but still). This means properties in classes are typed. What would the type of KeyNotFoundException.Key
be?
Dictionary<string, string> dict1 = new Dictionary<string, string>();
try
{
Console.WriteLine(dict1["one"]);
}
catch (KeyNotFoundException e)
{
// is e.Key a string?
}
Dictionary<int, int> dict2 = new Dictionary<int, int>();
try
{
Console.WriteLine(dict2[1]);
}
catch (KeyNotFoundException e)
{
// is e.Key an int?
}
If you wanted to properly support this, you'd have to use generics - KeyNotFoundException<string>
and KeyNotFoundException<int>
. But this would complicate the API just so you can get information you already have.

- 12,032
- 31
- 40
-
5
-
It could be an object and you would call ToString() on it as part of the message? You have a good point, but its not really a showstopper. – NeverStopLearning Apr 13 '17 at 09:08
-
1The code throwing the exception is responsible for formatting the message, including the work of calling `ToString()`. The result of the exception message is expected to be human-understandable. – rwong Apr 13 '17 at 10:23
-
How useful can be value `Namespace.SomeClass` . This what you get by default with `ToString' if key is of type `SomeClass`. – Fabio Apr 13 '17 at 21:46
-
3I don't think that an exception taking an object reference outside of it's expected code path is a good general solution. – Mike Apr 14 '17 at 01:14
This question involves digging into the history of .NET Framework design. As such,
- People who actually worked in the .NET Framework design team would be able to provide authoritative first-hand account of this question;
- People who don't have access to them, would not be able to provide first-hand account. All we could do is guessing.
I'll admit that I'm not, therefore my answer to this question is based on guessing.
In general, this makes this question not a good fit for this site. It is better to ask this question directly in front of a former .NET Framework design team member.
We'll review a few things here.
Available since .NET Framework 1.1:
Available since .NET Framework 2.0:
Changes that were made to existing classes since .NET Framework 2.0:
Explanation of invalid argument behavior in Dictionary
indexer:
- https://msdn.microsoft.com/en-us/library/9tee9ht2(v=vs.110).aspx
- Throws
ArgumentNullException
when key is null. - Throws
KeyNotFoundException
when the key does not exist in the collection.
- Throws
We can see that, KeyNotFoundException
was actually added to .NET Framework at a later time than ArgumentOutOfRangeException
. In other words, it is possible that it was a deliberate decision to omit the storing of the key into the exception object.
Some guesses are:
Maybe it was a security concern? The fear of deep low-level code encountering a key-not-found issue, storing the key into the exception being thrown, and the higher-level caller had a chance to see the key, thus revealing implementations in the low-level code? Such concerns were raised when the
(System.Exception).Data
property was added in .NET Framework 2.0.Maybe it was a boxing concern? When a non-reference type (e.g. a C#
struct
) is stored into a field of typeobject
(System.Object
), boxing occurs. A new object is created to box the struct, then the value of the struct is copied into the box.Maybe it was a need (guideline) to throw an exception of a different type? Microsoft's own guideline calls for throwing different types of exceptions for different (differentiating) reasons. Calling the
Dictionary
indexer getter with anull
throws anArgumentNullException
, therefore calling it with a non-null key that doesn't exist in that collection must throw something different?
Being guesswork, these guesses are possibly incorrect, and we might never know.

- 16,695
- 3
- 33
- 81