views:

87

answers:

4

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

+4  A: 

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

klausbyskov
We don't use Linq. We don't use databases at all. Where I can read more on the approach you suggested?
devdept
@devdept - that's linq to objects, not linq to sql. It has _nothing_ to do with databases.
Joel Coehoorn
+5  A: 

Try using a generic method:

void AddCars<T>(IEnumerable<T> collection) where T : IPainting
Nick Craver
Will this solution allow both Car[] and IPainting[] arrays to be passed to AddCars() ?
devdept
yes, it would allow that.
Joel Coehoorn
+4  A: 

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
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.
devdept
+2  A: 

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
Is the paintings.Cast<Car>() someway faster than a for loop that cast each object to the Car type? Thanks.
devdept
@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