10

如何向下转换对象列表,以便列表中的每个对象都向下转换为派生类的对象?

这就是场景。

我有一个带有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到派生项目之一。

当我有它们的列表时,问题就出现了。Listof是在BaseItem中声明的,BaseClass因为所有派生类都必须拥有它。但是在运行时访问它时,我似乎无法向下转换为派生类。

4

4 回答 4

11

使用 LINQ:

    var baseList = new List<BaseClass>();
    var derivedList = baseList.Cast<DerivedClass>();

注意:必须向下转换通常是一种“气味”,表明继承层次结构错误或错误实现。拥有基类的想法是您可以将所有子类视为超类,而不必向下转换为单个子类类型。

而不是Cast您可能想要使用OfType从超类集合中“捞出”某些派生类。但同样,应该没有必要这样做。

问问自己,为什么你需要一个子类——也许你需要将一些功能移动到基类?

于 2011-03-08T15:01:05.867 回答
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>

这将导致itemsinDerivedClass成为List<DerivedItem>where强制只能使用派生自的类型BaseItem

编辑:“向下转换”,将类型转换为派生类型,并不是您在这里真正想要做的。您的意图是派生列表对象通过设计使用特定的派生项类型,并且大概您希望将派生类型的实例化对象存储在派生列表类中。

因此,这可以在不使用泛型的情况下正常工作:List<BaseItem>完全能够存储从BaseItem. 但是,您必须使用强制转换(如其他答案中所述)从列表中引用这些对象才能访问派生属性。但这只是将一个对象“强制转换”为它的真实类型。泛型为您提供了一种直接提供对这些对象的强类型访问的方法。

基本上,将对象存储在作为对象超类的容器中并不会改变对象的任何内容——它只会改变代码引用它的方式,使其看起来是它派生的更简单的类型。

于 2011-03-08T14:59:28.210 回答
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 应该限制动物的类型。因此,这种设计不符合 Liskov 替换原则

于 2011-03-08T15:15:42.510 回答
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));

有关更多信息,请查看以下文章:

于 2015-09-23T02:48:32.440 回答