[英]Downcasting a list of objects in C#
如何向下转换对象列表,以便将列表中的每个对象向下转换为派生类的对象?
这就是场景。
我有一个基类,它有一个基本项List
,还有两个继承自它的类:
public class BaseClass
{
public List<BaseItem> items;
protected BaseClass()
{
// some code to build list of items
}
}
public class DerivedClass : BaseClass
{
public DerivedClass : base() {}
}
public class AnotherDerivedClass : BaseClass
{
public AnotherDerivedClass : base() {}
}
public class BaseItem {}
public class DerivedItem : BaseItem {}
public class AnotherDerivedItem : BaseItem {}
我们的想法是不必复制构建项目列表所需的代码。 BaseItem
具有我需要的所有基本内容,并且我总是可以将BaseItem
向下转换为其中一个派生项。
当我列出它们时会出现问题。 BaseItem
List
在BaseClass
声明,因为所有派生类都必须拥有它。 但是在运行时访问它时,我似乎无法向传播类转发。
使用LINQ:
var baseList = new List<BaseClass>();
var derivedList = baseList.Cast<DerivedClass>();
注意:通常需要向下转换是“气味”并指示继承层次结构错误或错误实现。 拥有基类的想法是,您可以将所有子类视为超类,而无需向下转换为单个子类类型。
您可能希望使用OfType
从超类集合中“ OfType
”某些派生类,而不是Cast
。 但同样,应该没有必要这样做。
问问自己,为什么需要一个子类 - 也许你需要将一些功能移到基类?
我相信你想要做的是使用泛型:
public class BaseClass<T> where T: BaseItem, new()
{
public List<T> items;
protected BaseClass()
{
items = new List<T>();
T item = new T();
item.SomePropertyOfBaseItem=something;
items.Add(item);
}
}
public class DerivedClass: BaseClass<DerivedItem>
这将导致DerivedClass
的items
为List<DerivedItem>
。 where
强制执行只能使用从BaseItem
派生的类型。
编辑 :“向下转换”,将类型转换为派生类型,并不是你想要在这里做的。 您的意图是派生列表对象按设计使用特定的派生项类型,并且可能您希望在派生列表类中存储派生类型的实例化对象。
因此,这可以在不使用泛型的情况下正常工作: List<BaseItem>
完全能够存储从BaseItem
派生的任何项目。 但是,您必须使用强制转换从列表中引用这些对象(如其他答案中所述),以便访问派生属性。 但这只是将一个对象“转换”为它的真实类型。 泛型为您提供了一种直接提供对这些对象的强类型访问的方法。
基本上,将对象存储在作为对象超类的容器中并不会改变对象的任何内容 - 它只会改变代码引用它的方式,使其看起来是从中派生的更简单的类型。
您还可以使用LINQ迭代基类的元素并向下转换每个元素,如下所示:
var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.ForEach(v => derivedList.Add((DerivedClass)v));
如果需要在转换之前检查每个元素的派生类型:
var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.OfType<DerivedClass>().ToList().ForEach(v => derivedList.Add(v));
有关更多信息,请查看以下文章:
public class Zoo
{
public List<Animal> items;
protected BaseClass()
{ // some code to build list of items }
}
public class PettingZoo : Zoo
{
public PettingZoo : base() {}
}
public class CatComplex : Zoo
{
public CatComplex : base() {}
}
public class Animal {}
public class Sheep : Animal {}
public class Tiger : Animal {}
...
PettingZoo myZoo = new PettingZoo();
myZoo.items.Add(new Tiger());
PettingZoo不能与Zoo互换,因为PettingZoo应该限制动物的类型。 因此,这种设计未能通过Liskov替代原则 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.