Nested Interfaces: Cast IDictionary<TKey, IList<TValue>> to IDictionary<TKey, IEnumerable<TValue>>?

最后都变了- 提交于 2019-12-20 03:23:08

问题


I would think it's fairly straightforward to cast an IDictionary<TKey, IList<TValue>> object to an IDictionary<TKey, IEnumerable<TValue>>, but

var val = (IDictionary<TKey, IEnumerable<TValue>>)Value;

throws a System.InvalidCastException, and

var val = Value as IDictionary<TKey, IEnumerable<TValue>>;

makes val null. What is the proper way to cast this?


回答1:


I would think it's fairly straightforward to cast an IDictionary<TKey, IList<TValue>> object to an IDictionary<TKey, IEnumerable<TValue>>

Absolutely not. It wouldn't be type-safe. Here's an example of why not:

// This is fine...
IDictionary<string, IList<int>> dictionary = new Dictionary<string, IList<int>>();

// Suppose this were valid...
IDictionary<string, IEnumerable<int>> badDictionary = dictionary;

// LinkedList<T> doesn't implement IList<T>
badDictionary["foo"] = new LinkedList<int>();

// What should happen now?
IList<int> bang = dictionary["foo"];

As you can see, that's going to cause problems - we'd be trying to get a LinkedList<int> out when we expect all the values to implement IList<int>. The point of generics is to be type-safe - so which line would you expect to fail? The first, third and fourth lines look pretty clearly valid to me - so the second one is the only one which can fail to compile, and it does...

Now in some cases, it can be done safely. For example, you can convert (in C# 4) from IEnumerable<string> to IEnumerable<object> because IEnumerable<T> only uses T in "output" positions.

See MSDN for more details.

EDIT: Just to clarify - it's easy to create a new dictionary with a copy of the existing key/value pairs, e.g. using link:

var copy = original.ToDictionary<TKey, IEnumerable<TValue>>(pair => pair.Key,
                                                            pair => pair.Value);

You just need to be aware that you now have two separate dictionaries.




回答2:


This may or may not help you, but I thought I'd throw it out as a supplement to Jon's answer.

If all you need is the dictionary's values, without reference to their keys, you can do this:

IDictionary<TKey, IList<TValue>> dictionary = Whatever();
var values = (IEnumerable<IEnumerable<TValue>>)dictionary.Values;

For this to work, you must be using C# 4.0 or later, and TValue must be constrained to be a reference type. Here's the code, slightly refactored, and with comments to explain:

IDictionary<TKey, IList<TValue>> dictionary = Whatever();

//Values returns an ICollection<IList<TValue>>
ICollection<IList<TValue>> temp1 = dictionary.Values;

//ICollection<T> inherits from IEnumerable<T>
IEnumerable<IList<TValue>> temp2 = temp1;

//IEnumerable<T> is covariant
//There is an implicit reference conversion between IList<T> and IEnumerable<T>
//So there is an implicit reference conversion between IEnumerable<IList<T>>
//and IEnumerable<IEnumerable<T>>
IEnumerable<IEnumerable<TValue>> values = temp2;


来源:https://stackoverflow.com/questions/10399568/nested-interfaces-cast-idictionarytkey-ilisttvalue-to-idictionarytkey-ie

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