Given the following types:
public interface IPrimary{ void doBattle(); }
// an ISecondary "is" an IPrimary
public interface ISecondary : IPrimary { }
// An implementation of ISecondary is also an IPrimary:
internal class SecondaryImpl : ISecondary
{
// Required, since this is an IPrimary
public void doBattle(){ }
}
Why can I not do this?
List<IPrimary> list = new List<ISecondary>();
This results in the following compilation error:
Argument type ‘System.Collections.Generic.List’ is not assignable to parameter type ‘System.Collections.Generic.List’
I understand the error, and I realize there are workarounds. I just do not see any clear reason why this direct conversion is disallowed. The values contained in a list of ISecondary, should after all, be (by extension) values of type of IPrimary.Why then are List<IPrimary> and List<ISecondary> being interpreted as unrelated types?
Can anyone explain clearly the reasoning for C# being designed this way?
A slightly extended example: I came across the issue when trying to do something similar to the following:
internal class Program
{
private static void Main(string[] args)
{
// Instance of ISecondary, and by extention, IPrimary:
var mySecondaryInstance = new SecondaryImpl();
// This works as expected:
AcceptImpl(mySecondaryInstance);
// List of instances of ISecondary, which are also,
// by extention, instances of IPrimary:
var myListOfSecondaries = new List<ISecondary> {mySecondaryInstance};
// This, however, does not work (results in a compilation error):
AcceptList(myListOfSecondaries);
}
// Note: IPrimary parameter:
public static void AcceptImpl(IPrimary instance){ }
// Note: List of type IPrimary:
public static void AcceptList(List<IPrimary> list){ }
}
Imagine that you had a method defined like this:
What would happen if you were to pass it a
List<ISecondary>as a parameter?The error that
List<ISecondary>is not assignable fromList<IPrimary>is the compiler’s way of getting you out of such troubles.