Is this a flaw in the Dictionary casting mechanism, or in my thinking that this should be allowed?
In your thinking. You are expecting that dictionaries should be covariant in their conversions. They are not, for the following reason. Suppose they were, and deduce what could go wrong:
Dictionary<int, List<string>> castMeDict =
new Dictionary<int, List<string>>();
Dictionary<int, IEnumerable<string>> getFromDict =
(Dictionary<int, IEnumerable<string>>)castMeDict;
castMeDict[123] = new List<string>();
IEnumerable<string> strings = getFromDict[123]; // No problem!
getFromDict[123] = new string[] { "hello" }; // Big problem!
An array of string is convertible to IEnumerable<string>
but not to List<string>
. You just put something that is not a list of string into a dictionary that can only take list of string.
In C# generic types may be covariant or contravariant if all the following conditions are met:
- You're using C# 4 or better.
- The varying generic type is an interface or delegate.
- The variance is provably typesafe. (The C# specification describes the rules we use to determine variance safety. C# 4.0 Version doc file can be downloaded [here]. See section 23.5.)
- The type arguments that vary are all reference types.
- The type has been specifically marked as safe for variance.
Most of those conditions are not met for dictionary -- it is not an interface or delegate, it is not provably safe, and the type is not marked as safe for variance. So, no variance for dictionaries.
IEnumerable<T>
by contrast does meet all those conditions. You can convert IEnumerable<string>
to IEnumerable<object>
in C# 4.
If the subject of variance interests you, consider reading my two dozen articles on the subject:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/