views:

445

answers:

4

I'm trying to write an extension method to insert data into a dictionary of dictionaries defined as follows:

items=Dictionary<long,Dictionary<int,SomeType>>()

What I have so far is:

    public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1,IDictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)
    {
        var leafDictionary = 
            dict.ContainsKey(key1) 
                ? dict[key1] 
                : (dict[key1] = new Dictionary<TKEY2, TVALUE>());
        leafDictionary.Add(key2,value);
    }

but the compiler doesn't like it. The statement:

items.LeafDictionaryAdd(longKey, intKey, someTypeValue);

gives me a type inference error.

For the statement:

items.LeafDictionaryAdd<long, int, SomeType>(longKey, intKey, someTypeValue);

I get "...does not contain a definition for... and the best extension method overload has some invalid arguments.

What am I doing wrong?

+2  A: 

Try to use a concrete type:

public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)

see the Dictionary<TKEY2,TVALUE> instead of IDictionary<TKEY2,TVALUE>

tanascius
+2  A: 

I'm guessing that this is a covariance / contravariance issue. Your method signature is expecting an IDictionary of IDcitionaries, but you're passing it an IDictionary of Dictionary. Try using a concrete Dictionary instead in your method signature, for the inner Dictionary.

BFree
It is not a guess - you are 100% correct.
Andrew Hare
+1  A: 

If you specify an IDictionary on your Parameter list for the Extension method, then your items will not match that.

Either change your Extension to

public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(
    this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,
    TKEY1 key1,
    TKEY2 key2,
    TVALUE value)

OR Try and cast your items to

((IDictionary<long, IDictionary<int, YourType>>)items).LeafDictionaryAdd(l, i, o);
Eoin Campbell
+5  A: 

Some inventive generic usage ;-p

class SomeType { }
static void Main()
{
    var items = new Dictionary<long, Dictionary<int, SomeType>>();
    items.Add(12345, 123, new SomeType());
}

public static void Add<TOuterKey, TDictionary, TInnerKey, TValue>(
        this IDictionary<TOuterKey,TDictionary> data,
        TOuterKey outerKey, TInnerKey innerKey, TValue value)
    where TDictionary : class, IDictionary<TInnerKey, TValue>, new()
{
    TDictionary innerData;
    if(!data.TryGetValue(outerKey, out innerData)) {
        innerData = new TDictionary();
        data.Add(outerKey, innerData);
    }
    innerData.Add(innerKey, value);
}
Marc Gravell
+1 For being clever. :)
Andrew Hare
Lovely. Thanks.
spender
That is some of the coolest code I have seen...nice work
CSharpAtl