我正在使用 C#.NET 3.5。我得到



使用以下(对于这个问题尽可能简化)代码:

using System.Collections.Generic;

namespace GenericsTest {
    class Program {
        static void Main(string[] args) {
            List<IAnimalStrategy<IAnimal>> strategies =
                new List<IAnimalStrategy<IAnimal>>();
            strategies.Add(new BarkStrategy());
        }
    }

    interface IAnimal { }
    interface IAnimalStrategy<T> where T : IAnimal { }
    class Dog : IAnimal { }
    class BarkStrategy : IAnimalStrategy<Dog> { }
}

最佳答案

你必须告诉编译器你的接口(interface)是协变的:IAnimalStrategy<out T>

namespace GenericsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<IAnimalStrategy<IAnimal>> strategies = new List<IAnimalStrategy<IAnimal>>();
            strategies.Add(new BarkStrategy());
        }
    }

    interface IAnimal { }
    interface IAnimalStrategy<out T> where T : IAnimal { }

    class Dog : IAnimal { }
    class BarkStrategy : IAnimalStrategy<Dog> { }
}

不幸的是,它仅在 C# 4.0 中可用:How is Generic Covariance & Contra-variance Implemented in C# 4.0?

为了理解这个问题,你可以忘记列表,这一行不会编译:
IAnimalStrategy<IAnimal> s = new BarkStrategy();
IAnimalStrategy<IAnimal> 接口(interface)可以在 IAnimal 上做一些事情,也许设置一个 IAnimal 类型的属性
interface IAnimalStrategy<T> where T : IAnimal
{
    T Animal {get; set;}
}

然后你就可以做类似的事情
IAnimalStrategy<IAnimal> s = new BarkStrategy();
s.Animal = new Cat();

它会吹在你的脸上。所以 C#3.5 不允许你这样做。
如果您说 T 与 out 关键字是协变的,C#4.0 将允许您这样做
interface IAnimalStrategy<out T> where T : IAnimal
{
    T Animal {get; set;}
}

这又要吹了



协变和逆变很难理解,我建议您阅读 Eric Lippert 博客上的精彩系列:Covariance and Contravariance in C#

关于c# - 通用参数不可分配,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19541699/

10-11 00:46