Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting a generic dictionary containing a generic dictionary

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?)

like image 532
nicodemus13 Avatar asked Apr 12 '11 13:04

nicodemus13


1 Answers

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.

like image 56
Eric Lippert Avatar answered Sep 30 '22 18:09

Eric Lippert