Reputation: 549
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
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
Reputation: 36
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
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
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