通用参数不可分配

Ruu*_*jah 4 c# generics

我正在使用C#.NET 3.5.我明白了

参数类型'GenericTest.BarkStrategy'不能赋值给参数类型'GenericsTest.IAnimalStrategy'

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

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

Cyr*_*don 13

你必须告诉编译器你的接口是协变的: 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> { }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,它仅在C#4.0中可用:如何在C#4.0中实现通用协方差和反差异?

要了解问题,可以忘记列表,这行不编译:

IAnimalStrategy<IAnimal> s = new BarkStrategy();
Run Code Online (Sandbox Code Playgroud)

IAnimalStrategy<IAnimal>接口可以IAnimal做的事情,也许设定类型的属性IAnimal

interface IAnimalStrategy<T> where T : IAnimal 
{
    T Animal {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以做类似的事情了

IAnimalStrategy<IAnimal> s = new BarkStrategy();
s.Animal = new Cat();
Run Code Online (Sandbox Code Playgroud)

它会吹在你的脸上.因此C#3.5不允许你这样做.
如果您说T与out关键字协变,C#4.0将允许您这样做

interface IAnimalStrategy<out T> where T : IAnimal 
{
    T Animal {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

这将再次打击,

方差无效:类型参数"T"必须在IAnimalStrategy.Animal'上无效.'T'是协变的.

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