Error passing Dictionary to IDictionary parameter
Why is there an error
Error 52 Argument 1: cannot convert from 'System.Collections.Generic.Dictionary>' to 'System.Collections.Generic.IDictionary>'
Dictionary<string, List<string>> tempResultIDList = new Dictionary<string,List<string>>();
test(tempResultIDList);
public bool test(IDictionary<string,IList<string>> a)
{
return true;
}
Re: Error passing Dictionary to IDictionary parameter
A List<string> is not the same as an IList<string>. Change the function to:
public bool test(IDictionary<string, List<string>> a)
and it will work as expected.
Re: Error passing Dictionary to IDictionary parameter
Well, when it comes to generics and polymorphism, the situation is rather complicated...
In contrast to what may be concluded from the above statement, List<string> is a kind of IList<string>, one being a type that implements the other.
I'm sure that Mutant_Fruit didn't make a claim to the contrary, but the brevity of his answer might introduce some confusion.
However, he is right in that, as far as C# is concerned,
IDictionary<string,IList<string>> is not a supertype of
IDictionary<string,List<string>> (which is what
Dictionary<string,List<string>> implements).
The problem is that it's a generic parameter, and when it comes to generics, figuring out what types can be safely passed as parameters can be rather counter-intuitive.
In your particular example:
Dictionary<string, List<string>> tempResultIDList = new Dictionary<string,List<string>>();
Here, you declare a dictionary which uses string for keys, and List<string> for values. This fact is very important in order to understand this.
Now consider if C# allowed you to pass it to your function, and do the following:
Code:
public bool test(IDictionary<string, IList<string>> dictionary)
{
string[] anArray = new string[] {
"this is not a List<string>",
"but it is an IList<string>" // string arrays implement IList<string>
};
dictionary.Add("arrayKey", anArray); // oops!!! Add() accepts any kind of IList<string>
}
Besides List<string> (or it's derivatives), there are other, unrelated types, like the string array used here, that may implement the IList<string> interface, and if you recall, the dictionary you declared expects the second parameter to be List<string> (or something that is derived from it), and not something else.
Now, in the case of the Dictionary<TKey, TValue> class, this probably isn't such a big deal, since this class probably doesn't call any of the methods specific to List<string>.
But you can imagine a different generic class, created for a different purpose, that actually does something with the value passed to it. For example, what if it calls some type-specific method? What if it tries, expecting a List<string> object, to delete an element, but it get's an array instead? Arrays don't provide such methods.
Even if the IList<string> interface could be used instead, an interface that does provide a Remove() method, in case of arrays, this would result in an NotSupportedException being thrown, again, because arrays don't support deletion of their elements - they have a fixed size.
So, bottom line is: C# considers Dictionary<TKey, TValue> to be a subtype of IDictionary<TKey, TValue>, but not of IDictionary<TKey, TIValue>, where TIValue is a supertype of (or an interface implemented by) TValue.
As you can see, whether you can or cannot pass a certain generic type parameter where its supertype is expected, depends on how is that type used, that is, depends on the implementation of the generic class.
This is why prior to C# 4.0, all such substitutions were banned. C# 4.0 loosened the grip a bit, providing syntax support for the developers (of generics) to specify what is safe to pass and what is not. This is called covariance and contravariance in generics, and you can read more about it here.
In any case, you should do as Mutant_Fruit suggested.