A System.Collections.Generic.Dictionary
is throwing KeyNotFoundException
, but I can't see which key is supposedly missing. How do I determine this?
"The given key was not present in the dictionary." A better way would be: "The given key '" + key.
A KeyNotFoundException is thrown when an operation attempts to retrieve an element from a collection using a key that does not exist in that collection. KeyNotFoundException uses the HRESULT COR_E_KEYNOTFOUND, which has the value 0x80131577.
The error 'The given key is not present in the dictionary' simply means that the dictionary does not have a value that corresponds to the key. So, this error would occur in the first line if InputParameters does not contain a key called "Target", or in the second line if there were no "name" in Attributes.
Custom exception:
class WellknownKeyNotFoundException : KeyNotFoundException
{
public WellknownKeyNotFoundException(object key, string message)
: this(key, message, null) { }
public WellknownKeyNotFoundException(object key, string message, Exception innerException)
: base(message, innerException)
{
this.Key = key;
}
public object Key { get; private set; }
}
Handy extension method:
public TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
try
{
return dic[key];
}
catch (KeyNotFoundException ex)
{
throw new WellknownKeyNotFoundException((object)key, ex.InnerException);
}
}
Usage:
var foo = new Foo();
var bar = new Bar();
IDictionary<Foo, Bar> dic = new Dictinary<Foo, Bar>
{
{ foo, bar }
};
try
{
dic.GetValue(foo);
}
catch (WellknownKeyNotFoundException ex)
{
var key = (Foo)ex.Key;
Assert.AreEqual(foo, key); // should be
}
There is no way to tell this from the exception. You need to implement your own solution for this.
If it is possible for you to customize the implementation where the dictionary is declared, you can easily replace System.Collections.Generic.Dictionary by a custom type throwing a nicer KeyNotFoundException. While this is similar to the answer of abatishchev, I don't like the extension method he introduced, since it means that we have two different ways to achieve the exactly same thing. This should be avoided if possible. I solved the problem by using a "NiceDictionary" instead, which can be used exactly like the original Dictinary used as base class. The implementation is almost trivial:
/// <summary>
/// This is a nice variant of the KeyNotFoundException. The original version
/// is very mean, because it refuses to tell us which key was responsible
/// for raising the exception.
/// </summary>
public class NiceKeyNotFoundException<TKey> : KeyNotFoundException
{
public TKey Key { get; private set; }
public NiceKeyNotFoundException(TKey key, string message)
: base(message, null)
{
this.Key = key;
}
public NiceKeyNotFoundException(TKey key, string message, Exception innerException)
: base(message, innerException)
{
this.Key = key;
}
}
/// <summary>
/// This is a very nice dictionary, because it throws a NiceKeyNotFoundException that
/// tells us the key that was not found. Thank you, nice dictionary!
/// </summary>
public class NiceDictionary<TKey, TVal> : Dictionary<TKey, TVal>
{
public new TVal this[TKey key]
{
get
{
try
{
return base[key];
}
catch (KeyNotFoundException knfe)
{
throw new NiceKeyNotFoundException<TKey>(key, knfe.Message, knfe.InnerException);
}
}
set
{
try
{
base[key] = value;
}
catch (KeyNotFoundException knfe)
{
throw new NiceKeyNotFoundException<TKey>(key, knfe.Message, knfe.InnerException);
}
}
}
}
As said, you can use it exaclty as you would use the original Dictionary. It magically works because of the overridden array operator ([]).
You can't just by looking at the exception. You will have to break into the debugger when the exception is thrown (Debug -> Exceptions... in Visual Studio) and see what key has been accessed. Alternatively you could catch the exception in code and print it out (e.g. to the console).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With