Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I cast a dictionary of one value type to dictionary of another value type when the value types can be cast from one another? [duplicate]

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

Why doesn't the below work?

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.

like image 576
user420667 Avatar asked Dec 19 '11 20:12

user420667


People also ask

Can a dictionary have different value types?

One can only put one type of object into a dictionary. If one wants to put a variety of types of data into the same dictionary, e.g. for configuration information or other common data stores, the superclass of all possible held data types must be used to define the dictionary.

Can we add duplicate keys in dictionary C#?

The Key value of a Dictionary is unique and doesn't let you add a duplicate key entry.

Which among the below options is the correct way to get the values in dictionary in C#?

foreach loop: You can use foreach loop to access the key/value pairs of the dictionary.As shown in the below example we access the Dictionary using a foreach loop.

Which elements must exist for each dictionary object?

A Dictionary object contains a set of key-item pairs. A dictionary's item is a value that is unambiguously associated with a unique key and the key is used to retrieve the item. The key can be of any type except a variant or an array (but generally it is a string or still an integer).


2 Answers

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/

like image 93
Eric Lippert Avatar answered Sep 28 '22 00:09

Eric Lippert


Research contravariance and covariance. For a particular example of why such a case could be a bad thing, check this answer by Jon Skeet.

like image 41
drharris Avatar answered Sep 28 '22 00:09

drharris