[英]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>
.如果Dog
是Animal
,这并不意味着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.