Casting a generic dictionary containing a generic dictionary

14,670

Solution 1

IDictionary does not support covariance.

Look here IDictionary<TKey, TValue> in .NET 4 not covariant

Solution 2

The other answers are right, but just to be crystal clear as to why this is illegal, consider the following:

interface IAnimal {}
class Tiger : IAnimal {}
class Giraffe : IAnimal {}
...
Dictionary<string, Giraffe> d1 = whatever;
IDictionary<string, IAnimal> d2 = d1; // suppose this were legal
d2["blake"] = new Tiger(); // What stops this?

No mortal hand can stop you putting a tiger into a dictionary of IAnimals. But that dictionary is actually constrained to contain only giraffes.

For the same reason you can't go the other way either:

Dictionary<string, IAnimal> d3 = whatever;
d3["blake"] = new Tiger(); 
IDictionary<string, Giraffe> d4 = d3; // suppose this were legal
Giraffe g = d4["blake"]; // What stops this?

Now you're putting a tiger in a variable of type giraffe.

Generic interface covariance is only legal in C# 4 if the compiler can prove that situations like this cannot arise.

Solution 3

The most you will be able to do is

IDictionary<string, Dictionary<string, bool>> viaInterface = someConcreteInstance

The reason your inner dictionary cannot be referenced differently here (or via a cast) is that while Dictionary<string, bool> is an IDictionary<string, bool>, not all IDictionary objects will be Dictionary objects. As such, obtaining a pure interface cast would then seemingly allow you to add other <string, IDictionary<string, bool>> pairs to the original collection, when clearly there could be type violations for the original object. Therefore, this is not supported.

Share:
14,670

Related videos on Youtube

nicodemus13
Author by

nicodemus13

Updated on June 04, 2022

Comments

  • nicodemus13
    nicodemus13 almost 2 years

    I have:

    var someConcreteInstance = new Dictionary<string, Dictionary<string, bool>>();
    

    and I wish to cast it to an interface version, i.e.:

    someInterfaceInstance = (IDictionary<string, IDictionary<string, bool>>)someConcreteInstance;
    

    'someInterfaceInstance' is a public property:

    IDictionary<string, IDictionary<string, bool>> someInterfaceInstance { get; set; }
    

    This compiles correctly, but throws a runtime casting error.

    Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.Collections.Generic.Dictionary`2[System.String,System.Boolean]]' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Collections.Generic.IDictionary`2[System.String,System.Boolean]]'.
    

    What am I missing? (Problems with the nested generic type/Property?)

  • nicodemus13
    nicodemus13 about 13 years
    Oh, is that the problem! (even in .net 4?) Do you have any suggestions on how to get the result I want?
  • Aliostad
    Aliostad about 13 years
    Depends what you are trying to do. Post another question on what you are trying to achieve and ask for the best design.
  • nicodemus13
    nicodemus13 about 13 years
    are you sure the last line is clear as you've written it? My original code compiles fine, but throws a runtime error, so the compiler seems to permit such situations.
  • Eric Lippert
    Eric Lippert about 13 years
    @nicodemus13: Your code has a cast operator in it; mine does not. The cast operator means "take this conversion which would have been illegal at compile time and make it legal; if it turns out to be illegal at runtime, throw an exception". And hey, guess what? That's what's happening. You're telling the compiler "assume that this illegal conversion is going to work out just fine" and then it doesn't, and you get an exception. The purpose of a reference type cast operator is to move the burden of type checking from the compiler to the runtime. The burden doesn't vanish, it just moves.
  • Jeffrey L Whitledge
    Jeffrey L Whitledge about 13 years
    "Giraffe, giraffe, burning bright/In the forests of the night". Good thing the C# type system prevents such tragedies as this!

Related