我有一个例子,我想要一个抽象类接口返回类似的东西
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<Animal>
,但是我想要返回的实际数据是IList<Lion>
、IList<Giraffe>
等,但是调用代码必须执行
GiraffeProcessor processor = new GiraffeProcessor();
IList<Animal> results = processor.GetResults();
这并没有给我一个伊利斯特,这正是我想要的。
问题
1) 以上代码不编译。长颈鹿处理器必须返回一个具体的List<Animal>
,您可以用Giraffe
对象填充它,但要返回的对象类型必须是List<Animal>
。不理想。
2) 返回结果时,只能得到IList<Animal>
,而不能得到IList<Giraffe>
。我已尝试使用显式转换为IList<Giraffe>
IList<Giraffe> results = (IList<Giraffe>) processor.GetResults();
这给出了一个运行时错误,可能是因为返回的对象不是IList<Giraffe>
,而是包含Giraffe
对象的IList<Animal>
。
有人能建议我在设计上做错了什么吗?因为我有点困惑于实现这一点的最佳方式。
怎么样:
abstract class AnimalProcessor<T> where T : Animal {
public abstract IList<T> ProcessResults();
}
class GiraffeProcessor : AnimalProcessor<Giraffe> {
public override IList<Giraffe> ProcessResults() {
return new List<Giraffe>();
}
}
class LionProcessor : AnimalProcessor<Lion> {
public override IList<Lion> ProcessResults() {
return new List<Lion>();
}
}
您可以通过使用泛型类型约束(例如)声明AnimalProcessor来解决此问题
public abstract class AnimalProcessor<T> where T : Animal
{
public abstract IList<T> ProcessResults();
}
如果这不起作用,您可以使用LINQ Cast运算符,例如:
public class GiraffeProcessor : AnimalProcessor
{
public override IList<Animal> ProcessResults()
{
return new List<Giraffe>().Cast<Animal>();
}
}
或者,将列表作为Animal存储在内部,但将Giraffe的添加到其中,例如
public class GiraffeProcessor : AnimalProcessor
{
private List<Giraffe> _innerList = new List<Giraffe>();
public override IList<Animal> ProcessResults()
{
return new List<Animal>(innerList ); }
}
致问候,
如果您使用C#4.0,您可以问自己处理器是否应该返回IEnumerable<T>
而不是IList<T>
。如果答案是"是",那么你可以从协方差中获利:
abstract class AnimalProcessor {
public abstract IEnumerable<Animal> ProcessResults();
}
class GiraffeProcessor : AnimalProcessor {
public override IEnumerable<Animal> ProcessResults() {
return new List<Giraffe>();
}
}
class LionProcessor : AnimalProcessor {
public override IEnumerable<Animal> ProcessResults() {
return new List<Lion>();
}
}
你有几个优点。首先,您可以将这些实现为迭代器块:
class GiraffeProcessor : AnimalProcessor {
public override IEnumerable<Animal> ProcessResults() {
yield break;
}
}
其次,不那么琐碎的是,您允许客户端代码决定将动物倾倒到什么样的集合中(如果有的话)。例如,考虑消费者可能想要LinkedList<Animal>
:
var animals = new LinkedList<Animal>(animalProcessor.ProcessResults());
或者考虑客户端可能只需要迭代序列:
foreach (var animal in animalProcessor.ProcessResults())
{ /*... do something ...*/ }
在任何一种情况下,如果您在ProcessResults中使用ToList()
调用,那么您将免费创建一个列表。如果消费者真的想要List<Animal>
,这可以很容易地实现:
var animals = new List<Animal>(animalProcessor.ProcessResults());
最后,您也可以从通用方法中受益,即使您更改了方法返回值的接口类型:
abstract class AnimalProcessor<T> where T : Animal {
public abstract IEnumerable<T> ProcessResults();
}
class GiraffeProcessor : AnimalProcessor<Giraffe> {
public override IEnumerable<Giraffe> ProcessResults() {
yield break;
}
}
class LionProcessor : AnimalProcessor<Lion> {
public override IEnumerable<Lion> ProcessResults() {
return Enumerable.Empty<Lion>();
}
}