C#类型转换:显式转换存在但引发转换错误?

时间:2016-07-21 11:40:32

标签: c# dictionary type-conversion ienumerable hashset

我了解到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):

  

无法隐式转换类型

     

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

     

存在显式转换(您是否错过了演员?)

但如果我通过写作

进行演员表
IDictionary<T, IEnumerable<T>> bar2 = (IDictionary<T, IEnumerable<T>>) bar;

然后我在运行时收到无效的强制转换异常。

两个问题:

  • 我该如何解决这个问题?是迭代密钥并逐步建立新字典的唯一方法吗?
  • 为什么我首先遇到此问题,即使HashSet确实实现了IEnumerable接口?

2 个答案:

答案 0 :(得分:5)

它不起作用的原因是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>,它会编译。但是,它不能成功,因为实际的值类型是HashSet<T>

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

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

答案 1 :(得分:3)

  

我该如何解决这个问题?是迭代密钥的唯一方法   一点一点地建立一个新词典?

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

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