简体   繁体   English

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

[英]Unable to hold generic interface implementations in list c#

How to make a list hold all the different implementations of generic interface?如何使列表包含通用接口的所有不同实现?

eg例如

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 }
}

I want to hold all the catcher in a list something like,我想把所有的捕手放在一个类似的列表中,

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()
     }
}

I know that it is something to deal with generic modifiers in c# (Covariance, Contravariance and Invariance) but unable to get it working.我知道在 c#(协方差、逆变和不变性)中处理通用修饰符是一件很困难的事情,但无法让它工作。

Tried: adding 'out' in尝试:在中添加“out”

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

but gives a compile time error:但给出编译时错误:

"The type parameter 'T' must be contravariantly valid on 'ICatcher.Catch(T)'. 'T' is covariant." “类型参数 'T' 必须在 'ICatcher.Catch(T)' 上逆变有效。'T' 是协变的。”

What am i doing wrong?我究竟做错了什么?

You need some type unification for animals, and you need to remove the generic declaration of ICatcher and make it a concrete type:您需要对动物进行一些类型统一,并且需要删除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);
}

Then you can have a collection of catchers like so:然后你可以有一个像这样的捕手集合:

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()
     }
}

ETA: Here's a repl.it demonstrating how it would be set up with interfaces. ETA:这是一个repl.it演示如何使用接口进行设置。 Although, in the respective Catch implementations, you are going to have to cast the IAnimal interface (if you need to access instance variables specific to a particular animal implementation)虽然,在各自的Catch实现中,您将不得不IAnimal接口(如果您需要访问特定于特定动物实现的实例变量)

If Dog is Animal , it doesn't mean that ICatcher<Dog> is ICatcher<Animal> .如果DogAnimal ,这并不意味着ICatcher<Dog>ICatcher<Animal> There is no any relationship between ICatcher<Dog> and ICatcher<Animal> . ICatcher<Dog>ICatcher<Animal>之间没有任何关系。

Microsoft made that decision to prevent run-time errors in case of contravariant T . Microsoft 做出该决定是为了防止在逆变T的情况下出现运行时错误。 Let's take a look:让我们来看看:

ICatcher<Dog> dogCatcher = new DogCatcher();
ICatcher<Animal> animalCatcher = dogCatcher; 

// Then, we can pass `Snake` as input to the `animalCatcher` which is actually `DogCatcher`
animalCatcher.Catch(new Snake()); // ???

For saying that ICatcher<Dog> is ICatcher<Animal> , we have to use out keyword in front of T which will say that ICatcher<T> is covariant in T. And it means T will be used only as return type inside your interface.要说ICatcher<Dog>ICatcher<Animal> ,我们必须在T前面使用out关键字,这表示ICatcher<T>在 T 中是协变的。这意味着T将仅用作界面内的返回类型. But, currently you are passing T as input to the Catch method.但是,目前您将T作为输入传递给Catch方法。

As your question does not say what the List is used for, I am making a wild guess at the problem you are trying to solve.由于您的问题没有说明 List 的用途,因此我对您要解决的问题进行了疯狂的猜测。

I expect what you need is我希望你需要的是

public interface ICatcher
{
     void MethodThatMakesYouListUseful()
}

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

AnimalCatchers = new List<ICatcher>();

As there is no useful type relationship between generic interfaces unless you define it yourself.因为除非您自己定义,否则泛型接口之间没有有用的类型关系。

Consider introducing an ICatcher interface.考虑引入一个ICatcher接口。 Then inherit it in your ICatcher<T> .然后在您的ICatcher<T>中继承它。

At the end create an IEnumerable<ICatcher> instead of IEnumerable<ICatcher<Animal>> .最后创建一个IEnumerable<ICatcher>而不是IEnumerable<ICatcher<Animal>>

Generics in Microsoft libraries have the same approach. Microsoft 库中的 Generics 具有相同的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM