开发者

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?


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


use the debuger (if needed check the ThrowOnCatch in Debug->Exceptions) and have a look


I used this extension method

internal static class KeyNotFoundExceptionExtensions
{
    public static string GetKeyValue(this KeyNotFoundException ex)
    {
        var match = Regex.Match(ex.Message, @"'(.*?)'");
        if (match.Success)
            return match.Groups[1].Value;

        throw ex;
    }
}


you would think that they could add the attempted key to the exception.data

this is what i did

        public static void SetGlobals()
    {
        string currentKey = "None";
        try
        {
            currentKey = "CurrentEnvironment";
            Globals.current_environment = Settings[currentKey];
            currentKey = "apiUrl";
            Globals.api_url = Settings[currentKey];
            currentKey = "whatever";
            Globals.whatever= Settings[currentKey];

            if (AppDomain.CurrentDomain.GetData(".devEnvironment") as bool? == true)
                Globals.api_url = "http://localhost:59164/api";
        }
        catch(KeyNotFoundException)
        {
            DBClass.logEvent("Error", "AppSettings", "Missing Setting: " + currentKey);
        }
    }


System.Collections.Generic.KeyNotFoundException has been thrown

If you are using DotNet Core with Xamarin Studio and you get this error you can check if the key exists with the following condition:

if (Application.Current.Properties.ContainsKey("userCredentials")) {
    //now process...
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜