在C#中向下转换对象列表

时间:2011-03-08 14:55:58

标签: c# inheritance downcast

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

这就是情景。

我有一个基类有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转发给其中一个派生项。

当我有一个列表时出现问题。 ListBaseItem的{​​{1}}在BaseClass中声明,因为所有派生类都必须拥有它。但是在运行时访问它时,我似乎无法向传播类转发。

4 个答案:

答案 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中的DerivedClassList<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));

有关详细信息,请查看以下文章: