泛型参数不可分配

本文关键字:可分配 不可分 参数 泛型 | 更新日期: 2023-09-27 18:36:37

我正在使用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> { }
}

泛型参数不可分配

你必须告诉编译器你的接口是协变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 中可用:如何在 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 不允许你这样做.
C#4.0 将允许你这样做,如果你说 T 与 out 关键字是协变

interface IAnimalStrategy<out T> where T : IAnimal 
{
    T Animal {get; set;}
}

这会再次吹,

无效方差:类型参数"T"必须始终有效动物战略"。"T"是协变。

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