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

发布于 2024-10-21 03:31:25 字数 792 浏览 6 评论 0原文

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

这就是场景。

我有一个带有基项列表的基类,以及从它继承的两个类:

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 向下转换为派生项之一。

当我有一个列表时,问题就出现了。 BaseItemList 是在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

在你怀里撒娇 2024-10-28 03:31:25

使用 LINQ:

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

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

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

问问自己,为什么需要子类 - 也许您需要将某些功能移至基类?

Using LINQ:

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

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 use OfType 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?

白芷 2024-10-28 03:31:25

我相信您想要做的是使用泛型:

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>

这将导致 DerivedClass 中的 items 成为 Listwhere 强制只能使用从 BaseItem 派生的类型。

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

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

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

I believe what you want to do is use generics:

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>

This will cause the items in DerivedClass to be List<DerivedItem>. The where enforces that only types that derive from BaseItem 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 from BaseItem. 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.

樱娆 2024-10-28 03:31:25
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 应该限制动物的类型。因此,此设计不符合里氏替换原则

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 is not interchangeable with Zoo, as a PettingZoo should restrict the types of Animals. As such, this design fails the Liskov substitution principle.

时光与爱终年不遇 2024-10-28 03:31:25

您还可以使用 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));

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

You can also use LINQ to iterate through the elements of the base class and downcast each element, like this:

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.ForEach(v => derivedList.Add((DerivedClass)v));

If you need to check the derived type of each element before casting:

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.OfType<DerivedClass>().ToList().ForEach(v => derivedList.Add(v));

For more information, take a look at the following articles:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文