Когда возникает KeyNotFoundException, как мне узнать, какой ключ не был найден?

System.Collections.Generic.Dictionary выбрасывает KeyNotFoundException , но я не вижу, какой ключ предположительно отсутствует. Как это определить?

31
задан abatishchev 29 August 2011 в 12:33
поделиться

3 ответа

Пользовательское исключение:

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; }
}

Удобный метод расширения:

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

Использование:

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
}
21
ответ дан 27 November 2019 в 22:28
поделиться

Если вы можете настроить реализацию, в которой объявлен словарь, вы можете легко заменить System.Collections.Generic.Dictionary на пользовательский тип, выдав более приятное KeyNotFoundException. Хотя это похоже на ответ Абатищева, мне не нравится метод расширения, который он ввел, поскольку это означает, что у нас есть два разных способа достичь абсолютно одинаковой цели. Этого следует избегать, если это возможно. Я решил проблему, используя вместо этого «NiceDictionary», который можно использовать точно так же, как исходный Dictinary, используемый в качестве базового класса. Реализация почти тривиальна:

/// <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);
            }
        }
    }
}

Как уже говорилось, вы можете использовать его точно так же, как вы бы использовали оригинальный словарь. Он волшебным образом работает из-за переопределенного оператора массива ([]).

5
ответ дан 27 November 2019 в 22:28
поделиться

Вы не можете просто смотреть на исключение. Вам придется взломать отладчик при возникновении исключения ( Debug -> Exceptions ... в Visual Studio) и посмотреть, к какому ключу был получен доступ. В качестве альтернативы вы можете перехватить исключение в коде и распечатать его (например, на консоли).

3
ответ дан 27 November 2019 в 22:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: