I have a good understanding of OOP in general, inheritance and polymorphism, interfaces, etc. I encountered a strange situation and I don't understand why it does not work at all...
EDIT : Ok, I found out that covariance (or contravariance?) may solve this problem, but crucially
How can I solve this without moving to C# 4.0 ?
Here is the situation. Given these two classes :
public class CustomCollectionType<T> : IEnumerable<T>
{
/* Implementation here, not really important */
}
public class Entity : EntityBase
{
/* Implentation here, not important */
}
The compiler complains when I try to have this generic method
public void LoopThrough(IEnumerable<EntityBase> entityList)
{
foreach(EntityBase entity in entityList)
{
DoSomething(entity);
}
}
And try to use it this way :
CustomCollectionType<Entity> entityList;
/* Add items to list */
LoopThrough(entityList);
Error says I cannot convert from CustomCollectionType<Entity>
to IEnumerable<EntityBase>
.
However, I can do this :
public void Foo(EntityBase entity)
{
entity.DoSomething();
}
Foo(new Entity());
And this :
public void Bar(IEnumerable<Entity> entityList)
{ ... }
CustomCollectionType<Entity> entityList;
Bar(entityList);
Why can't I create my method with the highest classes in the hierarchy? The types are obviously compatible... Am I missing something ?
EDIT : I want to solve this problem without altering the existing classes in any way, so creating a new method in any of the classes, or implementing an additional interface is out of the question.
Let's consider your first case. You have:
class Bowl<T> : IEnumerable<T> {}
class Apple : Fruit {}
...
void LoopThrough(IEnumerable<Fruit> fruits) ...
and you call
Bowl<Apple> apples = whatever;
LoopThrough(apples);
This fails in C# 3.0; it succeeds in C# 4.0 because IEnumerable<T>
is now covariant in T; a sequence of apples can be used as a sequence of fruits.
To make it work in C# 3.0 you can use the Cast
sequence operator.
Bowl<Apple> apples = whatever;
LoopThrough(apples.Cast<Fruit>());
To make it work in C# 2.0, implement the Cast sequence operator yourself. It is only a couple lines of code.
Note that in C# 4.0 it will still not be legal to say:
Bowl<Fruit> fruits = new Bowl<Apples>();
because of course you can say:
fruits.Add(new Orange());
and you just put an orange into a bowl that can only contain apples.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With