5

Suppose you have the following class:

class Car : IPainting
{
 ...
}

Then a function like this:

void AddCars(IEnumerable<Car> collection)

Then a code snippet like this:

Car bmw = new Car();
Car mercedes = new Car();

IPainting a = (IPainting) bmw;
IPainting b = (IPainting) mercedes;

IPainting[] paintings = new IPainting[] {a, b};

AddCars(paintings); // fails to compile

This of course doesn't compile because the AddCars() method accepts only a collection of Cars but it is what the 'paintings' array is made of.

I know that C# 4.0 will probably provide a solution for this. Is there any workaround today for it?

Thanks,

Alberto

abenci
  • 8,422
  • 19
  • 69
  • 134
  • 1
    C# 4.0 will not provide a solution for the code that you have here. You will never be able to pass something a type that is higher in the inheritance hierarchy to a method expecting something lower. As others have pointed out, your method would need to take in IPainting - not Car for this to work. – Keith Rousseau Jan 28 '10 at 14:45

4 Answers4

9

Try using a generic method:

void AddCars<T>(IEnumerable<T> collection) where T : IPainting
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
4

How about using Linq: AddCars(paintings.Cast<Car>());

Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
4

Your code is fundamentally flawed. Your class guarantees that all cars implement IPainting but there's no guarantee that all IPainting are cars.

You could likely make this work with some casting but I think you should reconsider your design.

AddCars(new Car[] { bmw, mercedes });
Chris Stavropoulos
  • 1,766
  • 13
  • 27
  • You are right, but I know that this is always true. Is there any way to enforce this? With a single Car object I can easily cast it to IPainting, the problem is I cannot do the same for collections. – abenci Jan 28 '10 at 14:09
3

C# 4 will not allow the code that you wrote, since the method AddCars expects an IEnumerable<Car> which implements IPainting. This does not mean that you can pass any class implementing IPainting (you could for instance have a class Bike : IPainting that has nothing to do with the Car class whatsoever. However, it will allow the other way around; if you have void AddCars(IEnumerable<IPainting> collection) you can pass a List<Car> to the method.

Until then, you will need to stick to passing Car sequences to the method, by using some casting mechanism (such as painting.Cast<Car>() suggested in other answers).

Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • Is the paintings.Cast() someway faster than a for loop that cast each object to the Car type? Thanks. – abenci Jan 29 '10 at 08:27
  • @devdept: Can't say; never did any performance comparisons on that. Would surprise if it it's not fast enough for most real-world scenarios though. – Fredrik Mörk Jan 29 '10 at 11:23