Unable to convert dictionary to IDictionary in method call

I cannot understand this for life. Let's say I have the following two dictionary objects:

// 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); 

The following statement creates a compile-time error that implicit conversion between Dictionary and IDictionary is not possible:

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

I need to do the conversion explicitly:

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

I don’t understand why the compiler cannot understand the covariance operation - the dictionary implements IDictionary - especially since something like this, of course, will work as we all know:

 IDictionary<string, int> d3 = d1; 

I'm sure there is a good reason for this behavior, and I'm curious what it is.

Update 1: To clarify, I'm curious about the behavior of not how to solve the problem. I know different solutions :)

Update 2: Thank you all for the great answers. I did not know that Tuple was invariant, and now I am doing it.

+4
source share
5 answers

The main problem is that the Tuple family is not covariant in its type arguments. This cannot be, because it is a class. A version of an interface or a delegate can be created that would be covariant, since there are no elements that accept type parameters at input positions.

This is easiest to see with Tuple<T1> :

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

This call:

 Tuple.Create(d1, d2); 

... prints both arguments of type Dictionary<string, int> , so you are trying to convert from Tuple<Dictionary<string, int>, Dictionary<string, int>> to Tuple<IDictionary<string, int>, IDictionary<string, int>> which does not work.

The as version changes the types of the arguments, so type inference gives the required type arguments, but it would be easier to just write the type arguments directly and completely exclude the output, according to Sebastian's answers:

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

If you use var at this point, this is not so bad:

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

Now the type x will be the Tuple<IDictionary<string, int>, IDictionary<string, int>> that you want.

EDIT: As noted in the comments, you can simply use the constructor at this point:

 var x = new Tuple<IDictionary<string, int>, IDictionary<string, int>>(d1, d2); 
+6
source

Are you trying to assign ...

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

... before...

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

... but Tuple<T1, T2> is a class and therefore an invariant .

+3
source

Type parameters for Tuple.Create are inferred from types, and therefore, the right side is a Tuple of two dictionaries, and it is a different type than Tuple IDictionarys - if you explicitly add type parameters to Tuple.Create to be of type IDictionary, everything should work like expected because this is normal for method parameters of a more specific type.

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

There is no conversion between Tuple<Dictionary<string, int>, Dictionary<string, int>> and a Tuple<IDictionary<string, int>, IDictionary<string, int>> since classes are in C # (and therefore the class Tuple<T1, T2> ) do not support covariance.

The compiler inferred the most specific return type for your call to Tuple.Create and does not use the type on the left side during exit.

+2
source

Try changing the type of the variable from Dictionary<string, int> to 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); 
0
source

Source: https://habr.com/ru/post/1445358/


All Articles