Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When KeyNotFoundException is thrown, how do I see which key wasn't found?

A System.Collections.Generic.Dictionary is throwing KeyNotFoundException, but I can't see which key is supposedly missing. How do I determine this?

like image 227
aknuds1 Avatar asked Aug 29 '11 12:08

aknuds1


People also ask

How do you solve the given key was not present in the dictionary?

"The given key was not present in the dictionary." A better way would be: "The given key '" + key.

What is key not found exception?

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.

What does the given key was not present in the dictionary mean?

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.


4 Answers

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
}
like image 155
abatishchev Avatar answered Oct 06 '22 20:10

abatishchev


There is no way to tell this from the exception. You need to implement your own solution for this.

like image 34
Daniel Hilgarth Avatar answered Oct 06 '22 22:10

Daniel Hilgarth


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 ([]).

like image 29
Till F. Avatar answered Oct 06 '22 20:10

Till F.


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).

like image 21
bitbonk Avatar answered Oct 06 '22 21:10

bitbonk