我正在使用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> { }
}
答案 0 :(得分: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> { }
}
不幸的是,它仅在C#4.0中可用:How is Generic Covariance & Contra-variance Implemented in C# 4.0?
为了解问题,你可以忘记列表,这行不编译:
IAnimalStrategy<IAnimal> s = new BarkStrategy();
IAnimalStrategy<IAnimal>
接口可以在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;}
}
这将再次打击,
无效方差:类型参数“T”必须是无效的 IAnimalStrategy.Animal”。 'T'是协变的。
协方差和反演法很难理解,我建议你阅读Eric Lippert博客上的精彩系列:Covariance and Contravariance in C#