C# 泛型列表中的数组协方差
我有一个示例,我希望抽象类接口返回类似这样的内容
abstract class AnimalProcessor {
public abstract IList<Animal> ProcessResults();
}
然后是具体示例
class GiraffeProcessor : AnimalProcessor {
public override IList<Animal> ProcessResults() {
return new List<Giraffe>();
}
}
class LionProcessor : AnimalProcessor {
public override IList<Animal> ProcessResults() {
return new List<Lion>();
}
}
问题是具体类需要具有相同的签名来重写 ProcessResults() 方法,因此它们需要返回 IList
,但是我想要返回的实际数据是 IList
、IList
等等,但是调用代码必须执行
GiraffeProcessor processor = new GiraffeProcessor();
IList<Animal> results = processor.GetResults();
Which 不会给我一个我想要的 Ilist 。
问题
1) 上面的代码无法编译。 giraffeProcessor 必须返回一个具体的 List
,您可以使用 Giraffe
对象填充它,但您构造的要返回的对象类型必须是 List
。不理想。
2)返回结果时,只能得到IList
,不能得到IList
。我尝试显式转换为 IList
IList<长颈鹿>结果 = (IList<长颈鹿>) 处理器.GetResults();
这会产生运行时错误,大概是因为返回的对象不是 IList
,而是一个包含 Giraffe
的 IList
对象。
任何人都可以建议我的设计在这里做错了什么,因为我对实现这一目标的最佳方法感到有点困惑。
I have an example where I want an abstract class interface to return something like this
abstract class AnimalProcessor {
public abstract IList<Animal> ProcessResults();
}
Then the concrete examples
class GiraffeProcessor : AnimalProcessor {
public override IList<Animal> ProcessResults() {
return new List<Giraffe>();
}
}
class LionProcessor : AnimalProcessor {
public override IList<Animal> ProcessResults() {
return new List<Lion>();
}
}
The problem is that the concrete classes need to have the same signature to override the ProcessResults()
method so they need to return an IList<Animal>
, however the ACTUAL data I want to return is an IList<Lion>
, IList<Giraffe>
etc, but then the calling code has to do
GiraffeProcessor processor = new GiraffeProcessor();
IList<Animal> results = processor.GetResults();
Which does not give me an Ilist which is what I want.
Problems
1) Above code does not compile. The giraffeProcessor has to return a concrete List<Animal>
, you can populate it with Giraffe
objects but the object type you construct to return has to be List<Animal>
. Not ideal.
2) When you return the results, you can only get an IList<Animal>
, not IList<Giraffe>
. I have tried casting explicitly to IList<Giraffe>
withIList<Giraffe> results = (IList<Giraffe>) processor.GetResults();
which gives a runtime error, presumably because the object returned is NOT an IList<Giraffe>
, it is an IList<Animal>
which CONTAINS Giraffe
objects.
Can anyone suggest what I am doing wrong here with my design as Im a bit stumped as to the best way to accomplish this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
怎么样:
How about:
您可以通过使用通用类型约束声明 AnimalProcessor 来解决此问题,例如,
如果这不起作用,您可以使用 LINQ Cast 运算符,例如:
或者,在内部将列表存储为 Animal,但向其中添加 Giraffe,例如
最好的问候,
You could resolve this by declaring AnimalProcessor with a generic type constraint, e.g.
If that doesnt work, you could use the LINQ Cast operator, for example:
Or, store the list internally as Animal but add Giraffe's to it, e.g.
Best regards,
如果您使用的是 C# 4.0,您可以询问自己处理器是否应该返回
IEnumerable
而不是IList
。如果答案是“是”,那么您可以从协方差中受益:您在这里有几个优势。首先,您可以将它们实现为迭代器块:
其次,更重要的是,您允许客户端代码决定将动物转储到哪种类型的集合中(如果有的话)。例如,考虑消费者可能想要一个
LinkedList
:或者考虑客户端可能只需要迭代序列:
无论哪种情况,如果您使用
ToList()
在 ProcessResults 中调用,您将毫无意义地创建一个列表。如果消费者确实想要一个List
,这可以很容易地完成:最后,即使您更改方法返回值的接口类型,您也可以从通用方法中受益:
If you are using C# 4.0, you can ask yourself whether the processor should return
IEnumerable<T>
rather thanIList<T>
. If the answer is "yes", then you can profit from covariance:You have a couple of advantages here. First, you could implement these as iterator blocks:
Second, and less trivially, you allow the client code to decide what kind of collection to dump the animals into -- if any. For example, consider that the consumer might want a
LinkedList<Animal>
:Or consider that the client might need only to iterate the sequence:
In either case, if you were using a
ToList()
call in ProcessResults, you'd be creating a list for nothing. If the consumer really wants aList<Animal>
, that can be accomplished very easily:Finally, you can also benefit from the generic approach, even if you change the interface type of the method's return value: