如何将苹果代表添加到水果代表列表中?

时间:2011-10-20 00:34:43

标签: c# generics delegates covariance contravariance

我有一个基本Fruit类和派生Apple类的示例程序。

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) { }
}

我希望有一个水果代表列表,并能够将更多派生水果的代表添加到列表中。我认为这与协方差或逆变有关,但我似乎无法弄明白。

错误消息是(没有名称空间):

The best overloaded method match for 'List<FruitDelegate<Fruit>>.Add(FruitDelegate<Fruit>)' has some invalid arguments`

1 个答案:

答案 0 :(得分:4)

FruitDelegate&lt; Fruit&gt; 是一个接受任何水果的代表。例如,以下内容有效:

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

您可以创建 FruitDelegate&lt; T&gt; contravariant的类型参数 T

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

允许您将 FruitDelegate&lt; Fruit&gt; 实例分配给 FruitDelegate&lt; Apple&gt; 变量:

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

这是有效的,因为委托引用了一种方法(其他水果)接受苹果。

但是,您无法将 FruitDelegate&lt; Apple&gt; 实例分配给 FruitDelegate&lt; Fruit&gt; 变量:

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

这是无效的,因为委托应该接受任何水果,但是会引用除了苹果之外不接受任何水果的方法。

结论:您无法将 FruitDelegate&lt; Apple&gt; 实例添加到 List&lt; FruitDelegate&lt; Fruit&gt;&gt; ,因为 FruitDelegate&lt; Apple&gt; 不是 FruitDelegate&lt; Fruit&gt;