Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add an apple delegate to a list of fruit delegates?

I have a sample program with a base Fruit class and a derived Apple class.

class Testy
{
    public delegate void FruitDelegate<T>(T o) where T : Fruit;

    private List<FruitDelegate<Fruit>> fruits = new List<FruitDelegate<Fruit>>();

    public void Test()
    {
        FruitDelegate<Apple> f = new FruitDelegate<Apple>(EatFruit);

        fruits.Add(f); // Error on this line
    }

    public void EatFruit(Fruit apple) { }
}

I want to have a list of fruit delegates and be able to add delegates of more derived fruit to the list. I believe this has something to do with covariance or contravariance but I cannot seem to figure it out.

The error message is (without namespaces):

The best overloaded method match for 'List<FruitDelegate<Fruit>>.Add(FruitDelegate<Fruit>)' has some invalid arguments`
like image 706
Ryan Peschel Avatar asked Oct 20 '11 00:10

Ryan Peschel


1 Answers

A FruitDelegate<Fruit> is a delegate that accepts any fruit. For example, the following is valid:

FruitDelegate<Fruit> f = new FruitDelegate<Fruit>(EatFruit);
f(new Apple());
f(new Banana());

You can make the type parameter T of FruitDelegate<T> contravariant:

public delegate void FruitDelegate<in T>(T o) where T : Fruit;

which allows you to assign a FruitDelegate<Fruit> instance to a FruitDelegate<Apple> variable:

FruitDelegate<Apple> f = new FruitDelegate<Fruit>(EatFruit);
f(new Apple());

This is valid, because the delegate refers to a method that (among other fruits) accepts apples.

However, you cannot assign a FruitDelegate<Apple> instance to a FruitDelegate<Fruit> variable:

FruitDelegate<Fruit> f = new FruitDelegate<Apple>(EatApple); // invalid
f(new Apple());
f(new Banana());

This is invalid, because the delegate should accept any fruit, but would refer to a method that accepts no fruit other than apples.

Conclusion: you cannot add a FruitDelegate<Apple> instance to a List<FruitDelegate<Fruit>>, because a FruitDelegate<Apple> is not a FruitDelegate<Fruit>.

like image 146
dtb Avatar answered Sep 29 '22 09:09

dtb