在继承的类中向下转换在基类中声明的对象

本文关键字:基类 声明 对象 转换 继承 | 更新日期: 2023-09-27 18:07:03

我正在为一个API创建一个插件,并且在继承方面有问题。是否有一种方法来"自动"向下cast对象,在基类中声明,在继承自它的类?

我的类结构如下:
abstract class MyPart
{
    public Part modelObject;
    ...
}
class MyPlate : MyPart
{
    public ArraList points; // from API
    ...
}
class Floor : MyPlate
{
    ...
}

Part是一个API类,其类结构如下:

class Part
class Plate : Part

现在,在我的代码在MyPlateFloor类我需要使用Plate modelObject来访问它的方法。目前我通过向下转换modelObject:

来做到这一点
(modelObject as Plate).doSomething;

这有点作用,尽管我想使它更简单。然而,主要问题是,当我试图访问modelObject的成员时,我无法将它们作为引用。例如,当我试图声明points时,它不会引用modelObject.points:

points = (modelObject as Plate).points;
points = null; // modelObject.points != null

是否有一种方法将变量声明为对modelObject的引用,以便它们可以被操纵?

在继承的类中向下转换在基类中声明的对象

这实际上是两个问题。为什么你的分数不会被删除,这个问题已经有了答案。但为了完整起见,这里是总结:

删除具有

调用var points = (modelObject as Plate).points时,复制了对modelObjectpoints对象的引用。对于points = null,您只需删除(null)对modelObjectpoints的引用,但modelObject仍然保留对points的引用。

删除modelObjectpoints的引用,调用(modelObject as Plate).points = null

子类

下转换

但是对于你的主要问题,如何在子类中自动向下转换对象。有两种方法可以做到这一点。方法隐藏泛型:

方法隐藏

将方法或基类的其他成员隐藏起来,并为名称提供新的含义。这样,您就可以赋予子类成员另一种含义和另一种返回类型。要实现这一点,您应该将modelObject封装在一个属性中。你的代码应该是这样的:

abstract class MyPart
{
    private Part modelObject;
    public Part ModelObject 
    {
       get { return modelObject; }
       set { modelObject = value; }
    }
    ...
}
class MyPlate : MyPart
{
    public new Plate ModelObject 
    {
        get { return base.ModelObject as Plate; }
        set { base.ModelObject = value; }
    public ArraList points; // from API
    ...
}
class Floor : MyPlate
{
    ...
}

注意,在子类中使用base.ModelObject。这使您仍然可以访问基类ModelObject,尽管您已经为ModelObject赋予了新的含义。除了方法重写之外,您可以保留基类Member,并且只提供具有相同名称的另一种含义。

注意,这有一些含义。最重要的一点是,类不知道成员是否隐藏在子类中,这意味着,转换为基类的子类将始终运行基类功能。为了说明目的,请参阅下面的代码示例。

public class Base 
{
    public void Do() 
    {
        Console.WriteLine("Base");
    }
}
public class Sub : Base
{
    public new void Do() 
    {
        Console.WriteLine("Sub");
    }
}
public class Program 
{
    public static void Main(string[] args) 
    {
        Sub sub = new Sub();
        Base base = sub;
        sub.Do(); //prints Sub
        base.Do(); //prints Base, even though it is the same object.
    }
}
泛型

另一方面,对于泛型,您可以使用类型参数对Plate的类型进行参数化(在示例中为TPlate)。这稍微复杂一点,但也是更干净的方式,因为子类化和强制转换没有像方法隐藏那样令人困惑的效果。
abstract class MyPart<TPart> 
    where TPart : Part //configure a type parameter
{
    public TPart modelObject;
    ...
}
class MyPlate : MyPart<Plate> //TPlate is now of type Plate
{
    public ArraList points; // from API
    ...
}
class Floor : MyPlate
{
    ...
}

上面的例子不允许MyFloor进一步专门化类型参数,但这也可以实现:

abstract class MyPart<TPart> 
    where TPart : Part //configure a type parameter and force it to be a subclass of Part
{
    public TPart modelObject;
    ...
}
class MyPlate<TPlate> : MyPart<TPlate> 
    where TPlate : Plate //force the type parameter to be a subclass of Plate
{
    public ArraList points; // from API
    ...
}
class Floor : MyPlate<Floor> //TType is now Floor
{
    ...
}

您正在创建引用的副本。所以points(modelObject as Plate).points指向相同的内存。当将null赋值给points时,会清除一个引用。另一个仍然存在。

如果您希望(modelObject as Plate).points;为空。直接使用:(modelObject as Plate).points = null;

当您将points设置为null时,您将取消作用域中名为"points"的引用,而不是实际变量。如果你真的不想只做modelObject.points = null(你通常只做CC_32),你想通过ref来实际访问它。

见https://msdn.microsoft.com/en-us/library/14akc2c7.aspx

也就是说,我不确定你为什么要把对象向下投射,因为我们看不清这里发生了什么