A Bogus
A Bogus

Reputation: 3930

Pass a List of a class into method with list of an abstract base class as a parameter (Covariance)

I have classes that inherit from an abstract base class, and I want to pass a List of any of those classes into a method that that has a List of the base class as a parameter. How can I make that happen?

Here is want I've tried -

public abstract class MyBaseClass {}

public class MyClass1 : MyBaseClass {}

//Inside another class
public void MyMethod(List<MyBaseClass> listOfBaseClass){}

//Inside another class
List<MyClass1> myClass1List = new List<MyClass1>();
MyMethod(myClass1List); //ERROR HERE, This method call does not compile

Is there anyway to accomplish what I am trying to do?

Upvotes: 3

Views: 769

Answers (3)

Jeppe
Jeppe

Reputation: 2276

You can also change the signature to be generic, and then constrain the generic type to be a subclass of your base class:

public void MyMethod<T>(List<T> listOfBaseClass) where T : MyBaseClass {}

Now you can pass a list of subclasses.

Upvotes: 0

felix-b
felix-b

Reputation: 8498

Declare your method with a parameter of type IReadOnlyList<T>.

You cannot receive List<T> or IList<T> because they are not read-only. If you could pass a List<MyClass1> argument into a method as a IList<MyBaseClass> parameter, the method could attempt to add a MyClass2 object into the list (assuming MyClass2 is another inheritor of MyBaseClass). It would be OK from the method's perspective, but it would cause runtime failure - so the C# language prevents it right off.

Your problem will be solved if you would use a read-only list. For example, a parameter of type IReadOnlyList<MyBaseClass> would accept argument of type List<MyClass1> - because List<T> implements IReadOnlyList<T>, and IReadOnlyList<T> declares T as out.

In this way you don't have to resort to IEnumerable<T>, and won't lose count and random access by index.

Upvotes: 1

StuartLC
StuartLC

Reputation: 107317

If you want to pass collections of derived types of MyBaseClass, you'll need to change the signature

public void MyMethod(List<MyBaseClass> listOfBaseClass){}

To a type which supports covariance, such as IEnumerable or IReadOnlyCollection, e.g.:

public void MyMethod(IEnumerable<MyBaseClass> listOfBaseClass){}

This is because List is invariant, whereas IEnumerable is covariant. The reason why the compiler is strict is because List allows for change to the collection, e.g. if MyMethod would be allowed to do this:

public void MyMethod(List<MyBaseClass> listOfBaseClass)
{
    listOfBaseClass.Add(new AnotherClass());
}

Where AnotherClass was another subclass of MyBaseClass, it would break the caller's collection which was supposed to be of List<MyClass1>();.

More about this here

Upvotes: 6

Related Questions