抛出KeyNotFoundException时,如何查看未找到哪个键?

akn*_*ds1 31 .net c# exception .net-4.0 keynotfoundexception

A System.Collections.Generic.Dictionary正在投掷KeyNotFoundException,但我看不出哪个密钥应该丢失.我该如何确定?

aba*_*hev 21

自定义例外:

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; }
}
Run Code Online (Sandbox Code Playgroud)

方便的扩展方法:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 不要构建自己的扩展方法,而是使用trygetvalue来获得更清晰的解决方案. (2认同)

Dan*_*rth 17

没有办法从异常中说出这一点.您需要为此实现自己的解决方案.

  • @ aknuds1:我不知道为什么它是这样设计的.我当然会把钥匙包括在内. (5认同)
  • 谢谢你澄清情况.但有点奇怪,异常无法通信吗?这个设计的任何已知理由? (4认同)
  • @Magnus:不是.键可能是异常上`object`类型的属性.有了这个,至少处理异常的代码可以分析丢失的密钥.但是由于你提到的原因,它可能不应该包含在异常消息中. (3认同)

Til*_* F. 5

如果您可以自定义声明字典的实现,则可以通过自定义类型轻松替换System.Collections.Generic.Dictionary,从而抛出更好的KeyNotFoundException.虽然这是类似于abatishchev的答案,我不喜欢他介绍了扩展方法,因为这意味着我们有两种不同的方式实现了完全相同的事情.如果可能,应该避免这种情况.我通过使用"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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如上所述,您可以像使用原始词典一样使用exaclty.由于重写的数组运算符([]),它神奇地起作用.

  • 应该提到的是,任何通过接口访问“NiceDictionary”的代码都会找到原始索引器,并且不会得到“NiceKeyNotFoundException”。这可以通过重新实现所有接口来解决,但代价是爆炸代码。 (2认同)