Jakub Mosakowski
Jakub Mosakowski

Reputation: 549

Pass derived class to method which use parent class c#

Today I took part in test in where was the task to add static method getMovingVehicles to already written code. I did it like you can see below, but after passing it online compiler I can see there are errors like:

Compilation error (line 28, col 39): The best overloaded method match for 'Rextester.Program.getMovingVehicles(System.Collections.Generic.List<Rextester.Vehicle>)' has some invalid arguments
Compilation error (line 28, col 57): Argument 1: cannot convert from 'System.Collections.Generic.List<Rextester.Car>' to 'System.Collections.Generic.List<Rextester.Vehicle>'
Compilation error (line 29, col 41): The best overloaded method match for 'Rextester.Program.getMovingVehicles(System.Collections.Generic.List<Rextester.Vehicle>)' has some invalid arguments
Compilation error (line 29, col 59): Argument 1: cannot convert from 'System.Collections.Generic.List<Rextester.Plane>' to 'System.Collections.Generic.List<Rextester.Vehicle>'

How should I pass derived class to method which uses parent class to make that work correctly?

namespace Rextester
{
 abstract class Vehicle{
    public int Speed; 
    }

     class Car: Vehicle{
     public String VIN;   
    }

     class Plane : Vehicle{
     public int altitude;   
    }

public class Program
{


    public static void Main(string[] args)
    {

        var cars= new List<Car>();
        var planes = new List<Plane>();
        List<Vehicle> movingCars= getMovingVehicles(cars);
        List<Vehicle> movingPlanes=getMovingVehicles(planes);

    }

     static List<Vehicle> getMovingVehicles(List<Vehicle> vehicles){
        List<Vehicle> movingVehicles=new List<Vehicle>();
        foreach( Vehicle v in vehicles){
        if(v.Speed>0)
             movingVehicles.Add(v);

        }

        return movingVehicles;
    }

}
}

Upvotes: 2

Views: 159

Answers (4)

FractalCode
FractalCode

Reputation: 380

You can convert the list or cast it using linq. Take a look at: this

You can do:

List<BaseClass> listOfBaseClass= new List<DerivedClass>().ConvertAll(x => (BaseClass)x);

Or:

List<BaseClass> listOfBaseClass = new List<DerivedClass>().Cast<BaseClass>().ToList();

Upvotes: 0

Another option is to use a generic

      static List<Vehicle> getMovingVehicles<T>(List<T> vehicles) where T:Vehicle {
            List<Vehicle> movingVehicles=new List<Vehicle>();
            foreach( Vehicle v in vehicles){
            if(v.Speed>0)
                 movingVehicles.Add(v);

            }

        return movingVehicles;
    }

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726539

The problem is not that you are passing derived class in place of a base class; that would be allowed. The problem is that you are passing a mutable collection of items of derived class, which is not allowed.

Fortunately, you are not treating the list of vehicles as a full list: you use only one aspect of it - namely, its ability to be enumerated. Therefore, you could replace List<Vehicle> with IEnumerable<Vehicle>, which is a lot more "forgiving". In particular, it lets you pass an IEnumerable<Car> in its place, as long as Car inherits from Vehicle:

static List<Vehicle> GetMovingVehicles(IEnumerable<Vehicle> vehicles) {
    return vehicles.Where(v => v.Speed != 0).ToList();
}

Note the use of LINQ to produce the results that you need without using a loop.

Upvotes: 3

jspcal
jspcal

Reputation: 51904

Simply change your function to take an IReadOnlyList<Vehicle>. The List<Vehicle> type is in-variant whereas IReadOnlyList<Vehicle> is co-variant, which accepts collections of the derived type:

static List<Vehicle> getMovingVehicles(IReadOnlyList<Vehicle> vehicles){

If this isn't possible, then you may convert your list to the appropriate type when passing it to the method:

getMovingVehicles(cars.ConvertAll(x => (Vehicle) x));

More info about covariance: https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

Upvotes: 0

Related Questions