views:

194

answers:

3

All I want is a dictionary which tells me which key it couldn't find, rather than just saying The given key was not present in the dictionary.

I briefly considered doing a subclass with override new this[TKey key], but felt it was a bit hacky, so I've gone with implementing the IDictionary interface, and passing everything through directly to an inner Dictionary, with the only additional logic being in the indexer:

public TValue this[TKey key]
{
    get
    {
        ThrowIfKeyNotFound(key);
        return _dic[key];
    }
    set
    {
        ThrowIfKeyNotFound(key);
        _dic[key] = value;
    }
}
private void ThrowIfKeyNotFound(TKey key)
{
    if(!_dic.ContainsKey(key))
        throw new ArgumentOutOfRangeException("Can't find key [" + key + "] in dictionary");
}

Is this the right/only way to go? Would newing over the this[] really be that bad?

+1  A: 

If you want to do this, you are going to have to roll your own in one way or another. But I'm going to question WHY you would want to do this?

Mitchel Sellers
Well, I thought I said why in the question. But rather than getting a mail from the guy doing the setup saying "which value did I get wrong?", I prefer him being able to fix it himself.
Benjol
+1  A: 

Instead of doing ContainsKey and checking for the presence of the key before touching the underlying dictionary, why not do

set {
    try {
        _dic[key] = value
    }
    catch (ArgumentOutOfRangeException) {
        throw new ArgumentOutOfRangeException(......);
    }
}

That way, you only pay for the extra chacking in the failure case - the success case, which is hopefully more common, doesn't have to do an extra dictionary lookup.

Stewart
+6  A: 

Sounds like a good fit for an extension method:

public static class SomeUtilClass {
    public static TValue VerboseGetValue<TKey, TValue>(
        this IDictionary<TKey, TValue> data, TKey key)
    {
        TValue result;
        if (!data.TryGetValue(key, out result)) {
            throw new KeyNotFoundException(
                "Key not found: " + Convert.ToString(key));
        }
        return result;
    }
}

This will then work on all your existing dictionaries whenever you call VerboseGetValue, for example:

    var data = new Dictionary<int, string> { { 123, "abc" } };
    Console.WriteLine(data.VerboseGetValue(123));
    Console.WriteLine(data.VerboseGetValue(456));
Marc Gravell
I'm so glad users #1 and #2 are on the right side of the planet :)
Benjol