嵌套接口:Cast IDictionary> to IDictionary

本文关键字:IDictionary TValue TK to IList TKey 接口 Cast 嵌套 | 更新日期: 2023-09-27 18:32:45

我认为将IDictionary<TKey, IList<TValue>>对象投射到IDictionary<TKey, IEnumerable<TValue>>相当简单,但是

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

抛出一个System.InvalidCastException,并且

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

使val为空。 正确的投射方法是什么?

嵌套接口:Cast IDictionary<TKey, IList<TValue>> to IDictionary<TK

我认为将IDictionary<TKey, IList<TValue>>对象投射到IDictionary<TKey, IEnumerable<TValue>>相当简单

绝对不行。它不是类型安全的。下面是一个为什么不这样做的示例:

// 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"];

如您所见,这会导致问题 - 当我们期望所有值都实现IList<int>时,我们会尝试LinkedList<int>出来。泛型的要点是类型安全的 - 那么你预计哪一行会失败?第一、第三和第四行对我来说很明显有效——所以第二行是唯一无法编译的行,而且确实......

现在在某些情况下,它可以安全地完成。例如,可以将(在 C# 4 中(从 IEnumerable<string> 转换为IEnumerable<object> IEnumerable<T>因为仅在"输出"位置使用T

有关更多详细信息,请参阅 MSDN

编辑:只是为了澄清 - 很容易创建一个带有现有键/值对副本的新字典,例如使用链接:

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

只需要知道您现在有两个单独的词典。

这可能会也可能不会帮助你,但我想我会把它作为乔恩答案的补充。

如果您只需要字典的值,而不引用它们的键,则可以执行以下操作:

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

为此,必须使用 C# 4.0 或更高版本,并且必须将 TValue 约束为引用类型。 这是代码,略微重构,并带有注释来解释:

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;