无法在列表C#中保存通用接口实现

kar*_*jan 5 c# generics covariance contravariance invariance

如何使列表包含通用接口的所有不同实现?

例如

public class Animal { // some Animal implementations }
public class Dog : Animal { // some Dog implementations }
public class Snake : Animal { // some Snake implementations }

public interface ICatcher<T> where T: Animal
{
    // different animals can be caught different ways.
    string Catch(T animal);
}

public class DogCatcher : ICatcher<Dog> 
{ 
    string Catch(Dog animal) { // implementation }
}

public class SnakeCatcher : ICatcher<Snake> 
{ 
    string Catch(Snake animal) { // implementation }
}
Run Code Online (Sandbox Code Playgroud)

我想将所有捕手都放在一个列表中,

public class AnimalCatcher
{
     // this will hold the catching method an animal catcher knows (just something similar)
     public IEnumerable<ICatcher<Animal>> AnimalCatcher = new List<ICatcher<Animal>>
     {
          new DogCatcher(),
          new SnakeCatcher()
     }
}
Run Code Online (Sandbox Code Playgroud)

我知道在c#中处理通用修饰符(协方差,相反和不变)是有些事情,但无法使其正常工作。

尝试:添加“出”

public interface ICatcher<out T> where T: Animal
{
    // different animals can be caught different ways.
    string Catch(T animal);
}
Run Code Online (Sandbox Code Playgroud)

但给出了编译时错误:

“类型参数'T'必须在'ICatcher.Catch(T)'上是反有效的。'T'是协变的。”

我究竟做错了什么?

gab*_*yes 2

您需要对动物进行某种类型统一,并且需要删除 的通用声明ICatcher并使其成为具体类型:

public interface IAnimal {}

public class Dog : IAnimal {}
public class Snake : IAnimal {}

public interface ICatcher
{
    // different animals can be caught different ways.
    string Catch(IAnimal animal);
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以拥有像这样的捕手集合:

public class AnimalCatcher
{
     // this will hold the catching method an animal catcher knows (just something similar)
     public IEnumerable<ICatcher> AnimalCatcher = new List<ICatcher>
     {
          new DogCatcher(),
          new SnakeCatcher()
     }
}
Run Code Online (Sandbox Code Playgroud)

ETA:这是一个repl.it,演示了如何使用接口进行设置。尽管在各自的Catch实现中,您将必须转换IAnimal接口(如果您需要访问特定于特定动物实现的实例变量)