How to pass List <Child> to a method with List <Parent> parameter?

I left inheritance briefly and need a little help.

I have an abstract base class Chief . There are two inheriting classes Ship and Vehicle , which have several properties through Chief .

I have a method that uses these common properties:

 public static void AssignRandomProperties(PSetList routeSettings, List<Chief> theChiefs) 

but when I try to convey

 List<Ship> 

or

 List<Vehicle> 

I was told that they cannot be converted. Here is an example method:

 ChiefRouteRandomizer.AssignRandomProperties(s.Route, theVehicles); 

I assumed, of course, that the List<Vehicle> would be treated as a List<Chief> when passed as an argument to AssignRandomProperties , but apparently not. Do I need to convert the list to List<Chief> ? If so, how?

+4
source share
4 answers

The first explanation. You cannot convert List<Vehicle> to List<Chief> because then the Add method would have the signature void List<Chief>.Add(Chief item) , and you could store instances of the Chief class in a list that was declared only for Storage Vehicle s. This will violate the type system; therefore it is not allowed.

The easiest way to get around this is to go through theVehicles.ToList<Chief>() . However, this will create a new list. This has two meanings: (1) you will waste memory duplicating the list and (2) if the method mutates the list itself (add / remove elements or replace members with other members), you will not see these changes in theVehicles list. (If the objects referenced in the list are the only changes, this is not a problem).

If you have control over the AssignRandomProperties method, use this signature instead:

 public static void AssignRandomProperties<T>( PSetList routeSettings, IList<T> theChiefs) where T : Chief { ... } 
+6
source

Look at this:

 List<Ship> ships = new List<Ship>(); List<Chief> asChiefs = (List<Chief>)ships; asChiefs.Add(new Car()); // so what, now ships[0] is a Car? 

That is why you cannot consider the list of ships as a list of leaders. If you want to know more about this, they say that List is not covariant (and it is also not contravariant).

Now, should your AssignRandomProperties method really take a List<T> ? If all you do is iterate, you do not need List<T> , you can do it with IEnumerable<T> , which is implemented by List<T> . The good thing here is IEnumerable<T> does not provide methods for modifying the list, so it is covariant (starting with .NET 4). This means you can do this:

 IEnumerable<Chief> chiefs = ships; 
+2
source

Here is my favorite trick

 public static void AssignRandomProperties<T>(PSetList routeSettings, List<T> theChiefs) where T : Chief 

Then you call the following

 AssignRandomProperties<Vehicle>(s.Route, theVehicles); 
0
source

Assuming the body of the method is as follows:

 public static void AssignRandomProperties(PSetList routeSettings, List<Chief> theChiefs) { foreach (var chief in theChiefs) { //assign some properties } } 

and provided that you use C # 4.0, which introduced covariance and contravariance, you could do this by avoiding the already proposed general solutions:

 public static void AssignRandomProperties(PSetList routeSettings, IEnumerable<Chief> theChiefs) { foreach (var chief in theChiefs) { //assign some properties } } 
0
source

Source: https://habr.com/ru/post/1332645/


All Articles