Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Verbose Dictionary" in C#, 'override new' this[] or implement IDictionary

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?

like image 776
Benjol Avatar asked Apr 27 '10 05:04

Benjol


3 Answers

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));
like image 118
Marc Gravell Avatar answered Sep 19 '22 17:09

Marc Gravell


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

get {
    try {
        return _dic[key];
    }
    catch (ArgumentOutOfRangeException) {
        throw new ArgumentOutOfRangeException(......);
    }
}

That way, you only pay for the extra checking in the failure case - the success case, which is hopefully more common, doesn't have to do an extra dictionary lookup. This is good for get, but set is more difficult since the default behaviour of set is to always work. If you don't want that then you would need to check for the existence of the key first.

like image 35
Stewart Avatar answered Sep 18 '22 17:09

Stewart


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?

like image 43
Mitchel Sellers Avatar answered Sep 17 '22 17:09

Mitchel Sellers