5

我这辈子都想不通。假设我有以下两个字典对象:

// Assume "query" is a LINQ queryable.
Dictionary<string, int> d1 = query.ToDictionary(k => k.Key, v => v.Value);
Dictionary<string, int>  d1 = query.ToDictionary(k => k.Key, v => v.Value);

以下语句会产生一个编译时错误,即无法在 Dictionary 和 IDictionary 之间进行隐式转换:

// Compile time error!
Tuple<IDictionary<string, int>, IDictionary<string, int>> = Tuple.Create(d1, d2);

我必须明确地进行转换:

Tuple<IDictionary<string, int>, IDictionary<string, int>> = Tuple.Create(d1 as IDictionary<string, int>, d2 as IDictionary<string, int>);

我不明白为什么编译器无法弄清楚协方差操作 - Dictionary 实现 IDictionary - 特别是因为我们都知道这样的事情当然会起作用:

IDictionary<string, int> d3 = d1;

我确信这种行为是有充分理由的,我很好奇它是什么。

更新1: 为了澄清,我对行为而不是如何解决问题感到好奇。我知道不同的解决方案:)

更新 2: 谢谢大家的精彩回答。我不知道Tuple是不变的,现在我知道了。

4

5 回答 5

6

基本上,问题在于该Tuple族的类型参数不是协变的。不可能,因为这是一门课。但是,可以创建协变的接口或委托版本,因为没有成员在输入位置接受类型参数。

这是最容易看到的Tuple<T1>

Tuple<string> stringTuple = Tuple.Create("Foo");
Tuple<object> objectTuple = stringTuple;

这个电话:

Tuple.Create(d1, d2);

... 将两个类型参数都推断为Dictionary<string, int>,因此您尝试从 转换Tuple<Dictionary<string, int>, Dictionary<string, int>>Tuple<IDictionary<string, int>, IDictionary<string, int>>,但这是行不通的。

具有更改参数类型的版本,as以便类型推断给出所需的类型参数 - 但根据塞巴斯蒂安的回答,直接编写类型参数并完全避免推断会更简单:

Tuple.Create<IDictionary<string, int>, IDictionary<string, int>>(d1, d2)

如果你var在这一点上使用,它还不错

var x = Tuple.Create<IDictionary<string, int>, IDictionary<string, int>>(d1, d2);

x现在将Tuple<IDictionary<string, int>, IDictionary<string, int>>是您想要的类型。

编辑:如评论中所述,您不妨在此时使用构造函数:

var x = new Tuple<IDictionary<string, int>, IDictionary<string, int>>(d1, d2);
于 2012-11-11T16:56:44.100 回答
3

您正在尝试分配...

Tuple<Dictionary<string, int>, Dictionary<string, int>>

...到...

Tuple<IDictionary<string, int>, IDictionary<string, int>>

...但是 theTuple<T1, T2>是一个类,因此是不变的。

于 2012-11-11T16:56:56.040 回答
2

Tuple.Create 的类型参数是从类型推断的,因此右侧是两个字典的元组,这是与 IDictionarys 元组不同的类型 - 如果您将类型参数显式添加到 Tuple.Create 为类型IDictionary 一切都应该按预期工作,因为方法参数可以是更具体的类型。

 Tuple.Create<IDictionary<string, int>,IDictionary<string, int>>(d1,d2)
于 2012-11-11T16:56:00.220 回答
2

Tuple<Dictionary<string, int>, Dictionary<string, int>>a和 a之间没有转换,Tuple<IDictionary<string, int>, IDictionary<string, int>>因为 C# 中的类(因此Tuple<T1, T2>该类)不支持协方差。

编译器已为您的调用推断出最具体的返回类型Tuple.Create,并且在推断期间不使用左侧的类型。

于 2012-11-11T16:56:49.437 回答
0

尝试将变量类型从更改Dictionary<string, int>IDictionary<string, int>.

IDictionary<string, int> d1 = query.ToDictionary(k => k.Key, v => v.Value);
IDictionary<string, int>  d1 = query.ToDictionary(k => k.Key, v => v.Value);
于 2012-11-11T16:49:55.720 回答