在 c# 中编写向上转换和向下转换表达式



我最近一直在研究 c# 中的上投和下投。我知道向上转换是指从派生类到基类的转换。但是,当我看到一个向上投射的实际示例(如下所示(时,我会感到困惑。

public class Shape 
{
...
}
public class Circle : Shape
{
...
}
Circle circle = new Circle();
Shape shape = new Shape();
// Converting an object into its base class reference
shape = circle

如果我们要将 circle 转换为它的基类引用,它不应该像

circle = shape 

对不起,如果听起来太业余了。这是因为我一直看到以下格式的表达式:

int x = 3; // means assign 3 to variable x. 

所以我只是很困惑为什么圆圈在右手边而不是左手边。请指教。把我当初学者。

(旁白:这称为向上转换,因为传统上,绘制类图时,基类在派生类的物理上显示

。现在,当您执行以下操作时:

shape = circle; // shape->(instance of Circle)

您正在将Circle引用分配给Shape引用,以便在分配后,引用shape将引用Circle

这很好,因为您可以使用Shape执行的所有操作也可以使用Circle

但是,如果您这样做:

circle = shape; // circle->(instance of Shape)

您正在将Shape引用分配给Circle引用。您无法这样做,因为(如果可能的话(您将能够访问Shape中不存在Circle功能。

例如,假设Circle.Radius存在,但Shape.Radius不存在。

如果允许您将circle引用指向Shape,那么如果您尝试访问circle.Radius会发生什么?答案是:未定义的行为会发生,因为Shape.Radius不存在。

问题是:Shape不是Circle,但CircleShape

这意味着Circle总是可以放置在需要Shape的地方,但是当您需要Circle时,您不能Shape将其放入其位置,因为它也可能是Triangle

这就是为什么您需要显式投射它(使用(Type)variablevariable as Type(。

本质上,让我们假设以下内容:

class Shape {}
class Circle : Shape {}
class Triangle : Shape {}

现在,我们还有一个Triangle,允许我们更好地布局:

Circle c = new Circle();
Triangle t = c; // Impossible due to Circle not being a Triangle
Shape s = c; // Possible because a Circle is a Shape
Triangle t2 = s; // Impossible because Shape may be a Triangle or any other derived class

你在示例中基本上所做的也可以写成如下:

Circle circle = new Circle();
Shape shape = (Shape)circle; //Casting the object to the base type

因此,您将类型为Circle的对象强制转换为类型为Shape的对象。 在您的代码中,这是"自动"完成的,因为您正在将值辅助到类型为Shape的新变量。

这进一步解释了强制转换/基类:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions

如果你了解 set,你可以很容易地理解为什么"形状 = 圆形"是可以的,而"圆形 = 形状"是不能的。

想一想。

A 是字母表的一个字符。

所以我们可以说

public class A : Alphabet
{
}

正如我们所知。

字母表也是

public class Alphabet
{
}

如果我们画一个图表,它可以是这样的

┌───────── Alphabet ───────┐
│ A B C D E ... a b c ... z│
└──────────────────────────┘

我们可以说z是Alphabet,但我们不能说Alplabet是z,因为Alphabet包含的不仅仅是z。

所以,让我们看看圆形和形状。

圆包含形状的信息,并添加了更多变量。(可能没有,但可以更改。

所以我们可以说圆是一组形状。

我们可以修改基于形状的圆形。我们也可以初始化圆。

但是如果你做"形状=圆形",圆中的某些东西就无法初始化。

它返回错误。

我将尝试解释:

变量shape包含对类型Shape的对象的引用

当您编写Shape shape = new Shape();变量shape将包含对新Shape对象的引用。

通过写入shape = circle重新分配shape时,它包含对另一个对象的引用。对象circle的类型是circle,但由于 circle 继承shape所以可以做这个赋值;对键入Shapecircle进行了隐式强制转换。

另一种也许更清晰的转换方法是制作明确的转换:

Circle circle = new Circle();
Shape circleAsShape = (Shape)circle;

Upcast意味着将对象的类型更改为派生较少的基类(Circle对象更改为Sape(。

向下铸造在另一个方向上工作,例如从Shape铸造到Circle.

派生类型较多的变量可以很容易地分配给派生类型较少的变量,因为向上转换在这里隐式完成,因为Circle也是一个Shape。这就是为什么可以将更多派生类型的值分配给派生类型较少的可值的原因。

相反,它不起作用,因为Shape是通用的,我们不知道它是否是Circle.因此,当您尝试向下转换时,您需要显式指定它:

// this won't work
Shape shape = new Shape();
Circle c = (Circle)shape;
// this will
Shape shape = new Circle();
// we know we have Circle object so we can downcast
Circle c = (Circle)shape;

最新更新