如何向下转换对象列表,以便将列表中的每个对象向下转换为派生类的对象?
这就是情景。
我有一个基类有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
转发给其中一个派生项。
当我有一个列表时出现问题。 List
中BaseItem
的{{1}}在BaseClass
中声明,因为所有派生类都必须拥有它。但是在运行时访问它时,我似乎无法向传播类转发。
答案 0 :(得分:7)
使用LINQ:
var baseList = new List<BaseClass>();
var derivedList = baseList.Cast<DerivedClass>();
注意:通常需要向下转换是一种“气味”,并指示继承层次结构错误或错误实现。拥有基类的想法是,您可以将所有子类视为超类,而无需向下转换为单个子类类型。
您可能希望使用Cast
从超类集合中“删除”某些派生类,而不是OfType
。但同样,应该没有必要这样做。
问问自己,为什么需要有一个子类 - 也许你需要将一些功能移到基类?
答案 1 :(得分:6)
我相信你想要做的是使用泛型:
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>
这会导致items
中的DerivedClass
为List<DerivedItem>
。 where
强制执行只能使用从BaseItem
派生的类型。
编辑:“向下转换”,将类型转换为派生类型,实际上并不是您要在此处执行的操作。您的意图是派生列表对象按设计使用特定的派生项类型,并且可能您希望在派生列表类中存储派生类型的实例化对象。
因此,这可以在不使用泛型的情况下正常工作:List<BaseItem>
完全能够存储从BaseItem
派生的任何项目。但是,您必须使用强制转换从列表中引用这些对象(如其他答案中所述),以便访问派生属性。但这只是将一个对象“转换”为它的真实类型。泛型为您提供了一种直接提供对这些对象的强类型访问的方法。
基本上,将对象存储在作为对象超类的容器中并不会改变对象的任何内容 - 它只会改变代码引用它的方式,使其看起来更简单。它衍生出来了。
答案 2 :(得分:0)
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应该限制动物的类型。因此,此设计失败the Liskov substitution principle。
答案 3 :(得分:0)
您还可以使用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));
有关详细信息,请查看以下文章: