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]

有些话、适合烂在心里 提交于 2019-11-26 20:58:50

问题


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.


回答1:


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/




回答2:


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




回答3:


Think about what would happen if it was allowed and you then did:

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

That's perfectly allowed; HashSet<string> implements IEnumerable<string> and can be added as a value to a Dictionary<int, IEnumerable<string>>. It can't though be added to a Dictionary<int, List<string>>, which is what that object really is.

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

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



来源:https://stackoverflow.com/questions/8567206/why-cant-i-cast-a-dictionary-of-one-value-type-to-dictionary-of-another-value-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!