嵌套接口:Cast IDictionary <tkey,ilist <tvalue =“”>&gt;到IDictionary <tkey,ienumerable <tvalue =“”>&gt;?</tkey,> </tkey,>

时间:2012-05-01 15:00:08

标签: c# generics interface casting

我认为将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为空。投这个的正确方法是什么?

2 个答案:

答案 0 :(得分:7)

  

我认为将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"];

正如您所看到的,这会导致问题 - 当我们期望所有值都实现LinkedList<int>时,我们会尝试获取IList<int>。泛型的要点是类型安全 - 那么你期望失败的那条线?第一行,第三行和第四行对我来说看起来非常有效 - 所以第二行是 only 一行无法编译,而且确实...

现在在一些案例中,可以安全地完成。例如,您可以将(在C#4中)从IEnumerable<string>转换为IEnumerable<object>,因为IEnumerable<T>仅在“输出”位置使用T

有关详细信息,请参阅MSDN

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

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

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

答案 1 :(得分:0)

这可能会或可能不会帮助你,但我认为我会把它作为Jon答案的补充。

如果你需要的只是字典的,而不参考它们的键,你可以这样做:

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;