Why can't a method declare return type `List<IMyInterface>` and return a concrete class implementing it

StackOverflow https://stackoverflow.com/questions/21307099

  •  01-10-2022
  •  | 
  •  

Question

I have the following interface

public interface IMyInterface
{
    // Some method and property signatures
}

I have the following class implementing the above interface

public class MyClass : IMyInterface
{
    // Some methods and properties as declared by IMyInterface
}

Then I have this method in some random class, that I want to return a list of objects implementing IMyInterface. In this particular implementation these objects are instances of MyClass.

public List<IMyInterface> getItems(int id)
{
    return new List<MyClass>();
}

This will result in a compile error (Visible in real time as well, in Visual Studio)

Cannot implicitly convert type 'System.Collections.Generic.List<MyClass>' to 'System.Collections.Generic.List<IMyInterface>'

I've searched the internet and finally found this thread C# Interfaces and Generic Lists I then ended up with the following method

public List<IMyInterface> getItems(int id)
{
    return new List<MyClass>().Cast<IMyInterface>().ToList();
}

This will compile, but to me it seem to be a really odd way to handle it; Casting a concrete class to an Interface. In the thread C# Interfaces and Generic Lists Aequitarum Custos comment to the accepted answer indicate that this should not have to be done.

Am I missing something or is this the way to do it?

Was it helpful?

Solution 2

This is because T parameter in List<T> is not covariant. But it is in IEnumerable<out T>:

out T

The type of objects to enumerate.

This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived.

So you can do this, if you'd consider to change signature of getItems:

public IEnumerable<IMyInterface> getItems(int id)
{
    return new List<MyClass>() as IEnumerable<IMyInterface>;
}

You can find more information about covariance and contravariance here.

OTHER TIPS

Because even though Base is a subtype of Parent, doesnt mean List<Base> is a subtype of List<Parent>. IList<T> is invariant in its generic parameter, and so is List<T> (c# doesn't support class variance, only interface variance).

Read more about covariance, contravariance and invariance here: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

If List<T> was covariant, and you were allowed to do this:

List<Parent> list = new List<Base>();

What would happen if you then did this?

list.Add(new OtherBase());

This would certainly be legal at compile time, but cause a runtime error.

Consider this example:

public interface IAnimal
{
}

public class Cat : IAnimal
{
}

public class Dog : IAnimal
{
}

And you equivalent method:

public List<IAnimal> getAnimals()
{
    return new List<Dog>();
}


// You just Dog'd a list of Cats
IEnumerable<Cat> cats = getAnimals();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top