在 C# 中向下转换对象列表
如何向下转换对象列表,以便列表中的每个对象都向下转换为派生类的对象?
这就是场景。
我有一个带有基项列表的基类,以及从它继承的两个类:
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
中声明的,因为所有派生类都必须拥有它。但是当在运行时访问它时,我似乎无法向下转换为派生类。
How can I downcast a list of objects so that each of the objects in the list is downcast to an object of a derived class?
This is the scenario.
I have a base class with a List
of base items, and two classes inheriting from it:
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 {}
The idea is to not have to duplicate the code needed to build the list of items. The BaseItem
has all the basic stuff I need, and I can always downcast BaseItem
to one of the derived items.
The problem arises when I have a list of them. The List
of BaseItem
is declared in the BaseClass
because all the derived classes have to have it. But when accessing it at runtime I can't seem to be able to downcast to the derived class.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用 LINQ:
注意:必须向下转型通常是一种“味道”,表明继承层次结构是错误的,或者是错误实现的。拥有基类的想法是,您可以将所有子类视为超类,而不必向下转换为单个子类类型。
您可能希望使用
OfType
从超类集合中“找出”某些派生类,而不是Cast
。但同样,应该没有必要这样做。问问自己,为什么需要子类 - 也许您需要将某些功能移至基类?
Using LINQ:
Note: Having to downcast usually is a 'smell' and indicates that the inheritance hierarchy is wrong, or wrongly implemented. The idea of having a base class is that you can treat all subclasses as superclass without having to downcast to individual subclass types.
Instead of
Cast
you might want to useOfType
to 'fish out' certain derived classes from a collection of superclasses. But again, there should be no need to do that.Ask yourself, why you need to have a subclass - maybe you need to move some functionality to base class?
我相信您想要做的是使用泛型:
这将导致
DerivedClass
中的items
成为List
。where
强制只能使用从BaseItem
派生的类型。编辑:“向下转型”,将类型转换为派生类型,并不是您真正想要在这里做的事情。您的意图是派生列表对象按设计使用特定的派生项类型,并且您可能希望将派生类型的实例化对象存储在派生列表类中。
因此,在不使用泛型的情况下,这也可以正常工作:
List
完全能够存储从BaseItem
派生的任何项目。但是,您必须使用转换(如其他答案中所述)从列表中引用这些对象,才能访问派生属性。但这只是将对象“转换”为其真实类型。泛型为您提供了一种直接提供对这些对象的强类型访问的方法。基本上,将对象存储在作为对象超类的容器中不会改变该对象的任何内容 - 它只会改变代码引用它的方式,使其看起来是其派生的更简单类型。
I believe what you want to do is use generics:
This will cause the
items
inDerivedClass
to beList<DerivedItem>
. Thewhere
enforces that only types that derive fromBaseItem
can be used.edit: "downcasting", casting a type to a derived type, isn't really what you are trying to do here. Your intent is that the derived list objects use a specific derived item type by design, and presumably you want to store instantiated objects of the derived type in your derived list class.
So, this could work just fine without using generics: the
List<BaseItem>
is perfectly capable of storing any items that derive fromBaseItem
. However, you would have to reference these objects from the list using casting (as described in the other answers) in order to access the derived properties. But that is simply "casting" an object to it's true type. Generics gives you a way to provide strongly typed access to these objects directly.Basically, storing an object in a container that is a superclass of the object doesn't change anything about the object - it only changes the way your code can refer to it, by making it appear to be the simpler type from which it derives.
...
PettingZoo 不能与 Zoo 互换,因为 PettingZoo 应该限制动物的类型。因此,此设计不符合里氏替换原则。
...
PettingZoo is not interchangeable with Zoo, as a PettingZoo should restrict the types of Animals. As such, this design fails the Liskov substitution principle.
您还可以使用 LINQ 迭代基类的元素并对每个元素进行向下转换,如下所示:
如果需要在转换之前检查每个元素的派生类型:
有关详细信息,请查看以下文章:
You can also use LINQ to iterate through the elements of the base class and downcast each element, like this:
If you need to check the derived type of each element before casting:
For more information, take a look at the following articles: