无法在方法调用中将字典转换为IDictionary

9ee*_*ee1 5 .net c# type-conversion covariance implicit-conversion

我不能为我的生活弄清楚这一点.假设我有以下两个字典对象:

// 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);
Run Code Online (Sandbox Code Playgroud)

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

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

我必须明确地进行转换:

Tuple<IDictionary<string, int>, IDictionary<string, int>> = Tuple.Create(d1 as IDictionary<string, int>, d2 as IDictionary<string, int>);
Run Code Online (Sandbox Code Playgroud)

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

IDictionary<string, int> d3 = d1;
Run Code Online (Sandbox Code Playgroud)

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

更新1: 只是为了澄清,我很好奇行为不是如何解决问题.我知道不同的解决方案:)

更新2: 谢谢大家的答案.我不知道Tuple是不变的,现在我做了.

Jon*_*eet 6

基本上,问题是该Tuple族在其类型参数中不是协变的.它不可能,因为它是一个类.接口或委托版本可以创建将被然而协变,因为没有成员接受在输入位置的类型的参数.

这是最简单的Tuple<T1>:

Tuple<string> stringTuple = Tuple.Create("Foo");
Tuple<object> objectTuple = stringTuple;
Run Code Online (Sandbox Code Playgroud)

这个电话:

Tuple.Create(d1, d2);
Run Code Online (Sandbox Code Playgroud)

...正在推断两种类型的参数Dictionary<string, int>,所以你试图转换Tuple<Dictionary<string, int>, Dictionary<string, int>>Tuple<IDictionary<string, int>, IDictionary<string, int>>,这是行不通的.

as更改参数类型的版本,以便类型推断提供所需的类型参数 - 但是直接编写类型参数更简单,并且完全避免推断,根据Sebastian的答案:

Tuple.Create<IDictionary<string, int>, IDictionary<string, int>>(d1, d2)
Run Code Online (Sandbox Code Playgroud)

如果你var在这一点上使用它,它并没有那么糟糕:

var x = Tuple.Create<IDictionary<string, int>, IDictionary<string, int>>(d1, d2);
Run Code Online (Sandbox Code Playgroud)

现在的类型xTuple<IDictionary<string, int>, IDictionary<string, int>>是你想要的.

编辑:如评论中所述,您可能只是在此时使用构造函数:

var x = new Tuple<IDictionary<string, int>, IDictionary<string, int>>(d1, d2);
Run Code Online (Sandbox Code Playgroud)