I'm wondering why I can't just cast (I have a vague idea this might have something to do with that co/contravariance stuff?), and am I forced to copy the elements of the first dictionary to a new one in order to get the type I want?
-
paste your code example.. you are probably not using Dictionary<> properly.. – MethodMan Jan 04 '12 at 21:27
-
2This has been answered many times as it's a very frequent question. The short answer is because a reference to Dictionary
> would allow you to add an T2[] array, which would be incorrect since the type is Dictionary – James Michael Hare Jan 04 '12 at 21:29> -
@James Michael Hare I see. Sorry for the duplicate; I'm sure someone will close it. – J Cooper Jan 04 '12 at 21:33
-
1This is rather trivial operation with the `ToDictionary` extension method. However, the result is a *new* Dictionary: `var d2 = d1.ToDictionary(kv => kv.Key, kv => kv.Value.AsEnumerable())` or so. – Jan 04 '12 at 21:36
-
@JCooper: No worries, I haven't found the duplicate yet - it may have been a subtle variation - but I tried to sum it up below, though not in the great detail Eric Lippert always provides in his answers... – James Michael Hare Jan 04 '12 at 21:40
3 Answers
You cannot do this because they aren't the same type. Consider:
var x = new Dictionary<string, List<int>>();
// won't compile, but assume it could...
Dictionary<string, IEnumerable<int>> xPrime = x;
// uh oh, would allow us to legally add array of int!
xPrime["Hi"] = new int[13];
Does this make sense? Because Dictionary<string, List<int>>
says the TValue
is List<int>
which means you can Add()
a List<int>
as a value. If you could cast this to a Dictionary<string, IEnumerable<int>>
it would mean the value type is IEnumerable<int>
which would mean you could Add()
any IEnumerable<int>
(int[]
, HashSet<int>
, etc) which would violate the original type.
So, a List<T>
can be converted to a IEnumerable<T>
reference because List<T>
implements IEnumerable<T>
, but that does not mean that Dictionary<TKey, List<TValue>>
implements/extends Dictionary<TKey, IEnumerable<TValue>>
.
Put more simply:
Dictionary<int, Dog>
Can't convert to
Dictionary<int, Animal>
Because the latter would allow you to add Cat, Squirrel, etc.

- 37,767
- 9
- 73
- 83
-
Makes sense; I'll make a copy then (I won't actually be modifying the resulting collection, but the type system doesn't know that). – J Cooper Jan 04 '12 at 21:44
-
JCooper: Cool, as pst mentioned above, you can use LINQ to do that for you, like: `Dictionary
> xPrime = x.ToDictionary(pair => pair.Key, pair => pair.Value.AsEnumerable());` – James Michael Hare Jan 04 '12 at 21:47
You can not cast, because it still is a Dictionary<T1, List<T2>>
Lets say
Dictionary<string, List<int>> d1 = new Dictionary<string, List<int>>();
Dictionary<string, IEnumerable<int>> d2 = (Dictionary<string, IEnumerable<int>>)d1; // this is the invalid cast
d2["one"] = new int[0]; // valid for d2
List<int> list1 = d1["one"]; // would fail

- 46,430
- 8
- 69
- 108
yes, it's an issue with covariance. I believe this was corrected with .net 4.0

- 7,589
- 1
- 24
- 45
-
4JasonMeckley: Not quite, you can convert a List
to an IEnumerable – James Michael Hare Jan 04 '12 at 21:32but you can't convert a Dictionary > to Dictionary > -
@JamesMichaelHare, thanks for clarifying. my assumption was wrong. – Jason Meckley Jan 04 '12 at 21:35
-
1