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

Rya*_*hel 7 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) { }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

dtb*_*dtb 4

FruitDelegate <Fruit>是接受任何水果的委托。例如,以下内容是有效的:

FruitDelegate<Fruit> f = new FruitDelegate<Fruit>(EatFruit);
f(new Apple());
f(new Banana());
Run Code Online (Sandbox Code Playgroud)

您可以使FruitDelegate<T>的类型参数T逆变:

public delegate void FruitDelegate<in T>(T o) where T : Fruit;
Run Code Online (Sandbox Code Playgroud)

它允许您将FruitDelegate<Fruit>实例分配给FruitDelegate<Apple>变量:

FruitDelegate<Apple> f = new FruitDelegate<Fruit>(EatFruit);
f(new Apple());
Run Code Online (Sandbox Code Playgroud)

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

但是,您不能将FruitDelegate<Apple>实例分配给FruitDelegate<Fruit>变量:

FruitDelegate<Fruit> f = new FruitDelegate<Apple>(EatApple); // invalid
f(new Apple());
f(new Banana());
Run Code Online (Sandbox Code Playgroud)

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

结论:您无法将FruitDelegate<Apple>实例添加到List<FruitDelegate<Fruit>>,因为FruitDelegate<Apple>不是 FruitDelegate<Fruit>。