BMT
BMT

Reputation: 41

Passing collections of derived objects in C#

I'm still getting my feet wet with OO and C#. I'm sure this is a simple question and I think I know the answer, but I want to be sure.

If I have a class called Car and another class called Ford which inherits from Car, and yet another class called Mustang which inherits from the Ford class.

Is it acceptable/possible to create a method that accepts a collection of Car objects and then when I call that method actually pass to that method a collection of Mustang (or Ford) objects since they are in fact Car objects?

My thought is that this should be possible, with the understanding that I would only be able to access Properties\Methods of the Car class. Am I way off base on this?

Also, if I am right, that you can do this: do you need to cast the Mustang collection to a Car collection in the call to the method?

Upvotes: 4

Views: 3079

Answers (4)

Jakob Möllås
Jakob Möllås

Reputation: 4369

You can do this, passing a List<Car> containing a Ford:s for example:

public void Test()
{
    // This works:
    var fords = new List<Car> {new Ford()};
    FixCars(fords);

    // This does not work (since you cannot pass non car-typed list):
    // var mustangs = new List<Ford> {new Ford()};
    // FixCars(fords);
}

public void FixCars(List<Car> cars)
{
    // Do stuff, for example check actual type and do specialized things:
    foreach (var car in cars)
    {
        var ford = car as Ford;
        if (ford != null)
            ford.Honk();
    }
}

public class Car 
{    
}

public class Ford : Car
{
    public void Honk() {}
}

Upvotes: 0

YoryeNathan
YoryeNathan

Reputation: 14522

Others have already explained various aspects of sending a collection of Mustangs as a parameter to a different method, then I'll just add in a little info which you might find useful as well.

If you have a collection of Cars List<Car> you can get only the Mustangs out of it by:

IEnumerable<Mustang> mstngs = cars.OfType<Mustang>();
List<Mustang> mstngsLst = mstngs.ToList();

And if you have a collection of Mustangs List<Mustang> you can cast them all into cars with:

IEnumerable<Car> cars = mstngs.Cast<Car>();
List<Car> carsLst = cars.ToList();

Converting back into a list is not a must, by the way. It depends on what you need to do with the collection.

Upvotes: 1

evanmcdonnal
evanmcdonnal

Reputation: 48114

If you're only going to access methods and properties in the Car class there is no reason to pass a list of Mustangs. Instead you should just deal with your Mustangs as if they were Cars. That's one of the main points of inheritance. You can simply create a list of type car List<Car> then add your Mustangs to it. Then pass the list of type Car. This is more extensible because it can accept any object which inherits from Car and since you're only using properties/methods from Car it's as strict of a definition as you need.

If you want specific behavior in the Mustang class but a common interface for invoking that behavior define the method in Car then override it in Mustang. Again, this is more extensible because when you create a NineEleven class you can also override this method thus giving you different behavior in the child classes without actually exposing their type.

Upvotes: 0

Servy
Servy

Reputation: 203827

No, that's not possible.

So if we have a function that accepts a List<Car> types. Clearly that function ought to be able to add a Prius to that list, no? Well, if you were allowed to pass a List<Mustang> to this method you'd have just added a Prius to a List<Mustang>, clearly that would be bad.

Now if, rather than passing a List, the method had a parameter of IEnumerable or one of certain other read only collection types then it's possible it's "covariant". In that case, you could accept, as an example, an IEnumerable<Car> and pass it a List<Mustang> because you're never adding to the list, you're only accessing various elements, and as long as all of the Mustang objects are Car objects that's not a problem.

The design also seems a bit...off. I wouldn't think that Ford should inherit from Car. Ford isn't a car, it's a brand, a company, a type of car. Mustang is a car, so it makes sense for it to inherit from one. I would create a new type, say Manufacturer of which you could create Ford, Toyota, etc. and make that a (read only) property of Car.

Upvotes: 5

Related Questions