Why can't I use a dictionary of one type of value for a dictionary of another type of value when the types of values ​​can be cast apart?

Possible duplicate:
In C #, why can't a List <string> object be stored in a list <object> variable

Why doesn’t work below?

List<string> castMe = new List<string>(); IEnumerable<string> getFromCast = (IEnumerable<string>)castMe; // allowed. Dictionary<int, List<string>> castMeDict = new Dictionary<int, List<string>>(); Dictionary<int, IEnumerable<string>> getFromDict = (Dictionary<int, IEnumerable<string>>)castMeDict; // Not allowed 

Is this a flaw in the Dictionary casting mechanism or in my thinking that this should be allowed?

Thanks.

+9
source share
3 answers

Is this a flaw in the vocabulary casting mechanism or, in my opinion, should it be allowed?

In your thinking. You expect dictionaries to be covariant in their transformations. They are not for the following reason. Suppose they were, and deduce what might 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! 

The string array is converted to IEnumerable<string> , but not to List<string> . You simply put what is not a list of strings in a dictionary that can only accept a list of strings.

In C #, generic types can be covariant or contravariant if all of the following conditions are true:

  • You use C # 4 or better.
  • A different common type is an interface or delegate.
  • Deviation is provably typical. (The C # specification describes the rules we use to determine the safety of variance. The C # 4.0 version of the doc file can be downloaded [here] . See Section 23.5.)
  • Type arguments that change are reference types.
  • The type has been specifically marked as safe for rejection.

Most of these conditions are not met for the dictionary - it is not an interface or a delegate, it is not safe, and the type is not marked as safe for dispersion. Thus, there is no variance for dictionaries.

IEnumerable<T> , in contrast, satisfies all of these conditions. You can convert IEnumerable<string> to IEnumerable<object> in C # 4.

If the subject of disagreement interests you, consider reading my two dozen articles on this subject:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

+22
source

The study of contravariance and covariance. For a specific example of why such a case might be bad, check out this answer by Jon Skeet .

+4
source

Think about what happens if it is allowed, and then you did:

 getFromDict.Add(34, new HashSet<string>); 

This is fully permitted; HashSet<string> implements IEnumerable<string> and can be added as a value to Dictionary<int, IEnumerable<string>> . It cannot be added to Dictionary<int, List<string>> , which is actually the case.

If you want to use it as read-only IDictionary<int, IEnumerable<string>> , then you can get good performance from a wrapper class that goes to IEnumerable<string> as it appears.

Otherwise, you need to copy the values ​​to the new Dictionary<int, IEnumerable<string>> .

+2
source

All Articles