【问题标题】:C# type conversion: Explicit cast exists but throws a conversion error?C# 类型转换:存在显式转换但引发转换错误?
【发布时间】:2016-11-24 23:48:14
【问题描述】:

我了解到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&lt;T, System.Collections.Generic.HashSet&lt;T&gt;&gt;System.Collections.Generic.IDictionary&lt;T, System.Collections.Generic.IEnumerable&lt;T&gt;&gt;.

存在显式转换(您是否缺少演员表?)

但是如果我通过写作来进行演员表

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

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

两个问题:

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

【问题讨论】:

  • IEnumerable&lt;T&gt;covariantIDictionary&lt;TKey,TValue&gt; 不是。 外部类型很重要

标签: c# dictionary type-conversion ienumerable hashset


【解决方案1】:

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

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

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);

Dictionary cast 不起作用的原因是因为IEnumerable 是协变的,请注意声明中的&lt;out T&gt;

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

【讨论】:

    【解决方案2】:

    它不起作用的原因是IDictionary&lt;TKey, TValue&gt; 中的值不是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&lt;T&gt; 会起作用,因为它可以编译假定值类型为IEnumerable&lt;T&gt;。但它不会成功,因为 actual 值类型是 HashSet&lt;T&gt;

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      • 2019-07-13
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      相关资源
      最近更新 更多