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;
然后我在 运行 时得到一个无效的转换异常。
两个问题:
- 我该如何解决这个问题?唯一的方法是迭代键并一点一点地建立一个新的字典吗?
- 为什么我首先会遇到这个问题,即使
HashSet
确实实现了 IEnumerable
接口?
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());
我了解到 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>>
toSystem.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;
然后我在 运行 时得到一个无效的转换异常。
两个问题:
- 我该如何解决这个问题?唯一的方法是迭代键并一点一点地建立一个新的字典吗?
- 为什么我首先会遇到这个问题,即使
HashSet
确实实现了IEnumerable
接口?
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());