C# 类型转换:存在显式转换但抛出转换错误?

C# type conversion: Explicit cast exists but throws a conversion error?

我了解到 HashSet 实现了 IEnumerable 接口。因此,可以将 HashSet 对象隐式转换为 IEnumerable:

HashSet<T> foo = new HashSet<T>();
IEnumerable<T> foo2 = foo; // Implicit cast, everything fine.

这也适用于嵌套的泛型类型:

HashSet<HashSet<T>> dong = new HashSet<HashSet<T>>();
IEnumerable<IEnumerable<T>> dong2 = dong; // Implicit cast, everything fine.

至少我是这么想的。但是如果我做一个Dictionary,我运行就出问题了:

IDictionary<T, HashSet<T>> bar = new Dictionary<T, HashSet<T>>();
IDictionary<T, IEnumerable<T>> bar2 = bar; // compile error

最后一行给出了以下编译错误 (Visual Studio 2015):

Cannot implicitly convert type

System.Collections.Generic.IDictionary<T, System.Collections.Generic.HashSet<T>> to System.Collections.Generic.IDictionary<T, System.Collections.Generic.IEnumerable<T>>.

An explicit conversion exists (are you missing a cast?)

但是如果我通过写作来进行转换

IDictionary<T, IEnumerable<T>> bar2 = (IDictionary<T, IEnumerable<T>>) bar;

然后我在 运行 时得到一个无效的转换异常。

两个问题:

How do I solve this? Is the only way to iterate over the keys and build up a new dictionary bit by bit?

这可能不是最优雅的解决方案,但它确实有效:

IDictionary<T, HashSet<T>> bar = new Dictionary<T, HashSet<T>>();
IDictionary<T, IEnumerable<T>> bar2 = bar.ToDictionary(x => x.Key, y => (IEnumerable<T>)y.Value);

字典转换不起作用的原因是因为 IEnumerable 是协变的,请注意声明中的 <out T>

public interface IEnumerable<out T> : IEnumerable

IDictionary 不是。

public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable

您可以在这里阅读更多相关信息:https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx

它不起作用的原因是 IDictionary<TKey, TValue> 中的值不是 co-variant(出于同样的原因,密钥也不是)。如果允许的话,那么这段代码可以编译,但是 导致异常:

IDictionary<T, HashSet<T>> foo = new Dictionary<T, HashSet<T>>();
IDictionary<T, IEnumerable<T>> bar = foo;
foo.Add(key, new List<T>());

你会认为添加 List<T> 会起作用,因为它会编译给定的值类型应该是 IEnumerable<T>。但是,它无法成功,因为 actual 值类型是 HashSet<T>.

所以,是的:唯一的方法是创建一个新词典。

var bar = foo.ToDictionary(x => x.Key, x => x.Value.AsEnumerable());