繁体   English   中英

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

[英]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 ListBaseClass声明,因为所有派生类都必须拥有它。 但是在运行时访问它时,我似乎无法向传播类转发。

使用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>

这将导致DerivedClassitemsList<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM