为什么我们需要将派生类的对象分配给基类来调用方法?

hem*_*ant 4 c# polymorphism inheritance overriding

我有一个名为Shape的基类和一个派生类Rectangle,它派生自Shape.

class Shape
{
    public virtual void Draw()
    { 
        //Draw the Shape
        Console.WriteLine("Draw the Shape");
    }
}
class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Draw Rectangle");
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个非常基本的疑问,当我调用派生类的方法时,我会做这样的事情.

Shape r1 = new Rectangle();
r1.Draw();
Run Code Online (Sandbox Code Playgroud)

但是如果我想调用Rectangle类的方法,我总是可以这样做.

Rectangle r2 = new Rectangle();
r2.Draw();
Run Code Online (Sandbox Code Playgroud)

我的问题是,当我们总能使用易于理解和实现的第二种方法时,为什么我们需要使用第一种方法.

kas*_*rch 6

两种方法都是正确的,两者都有效.在这两种情况下,都会调用-class 的Draw-method Rectangle.

第一个让你想到为什么要使用第一种方法的场景,就是当你有某种类型的集合时,你想要一次性绘制它们.假设您添加更多派生类,Circle以及Triangle谁也覆盖基本实现Draw.那么以下仍然是一个有效的场景:

//We know that our collection will contain various shapes.
List<Shape> shapes = new List<Shape>();

//This is okay because all the specific shapes inherit from the Shape class.
shapes.Add(new Triangle());
shapes.Add(new Rectangle());
shapes.Add(new Circle());

//We can safely draw all shapes, because all shapes have a Draw-method.
//If they haven't implemented their own, the Draw-method of the Shape class will be called.
foreach(Shape shape in shapes)
  shape.Draw();
Run Code Online (Sandbox Code Playgroud)

要记住的一件事是,在上面的例子中,我们将所有特定对象视为类型Shape.这实质上意味着在该用法中,每个对象都不知道任何特定于类的实现.假设您NumberOfCorners为自己添加了一个-property Rectangle:

class Rectangle : Shape
{
    public Rectangle() {
        NumberOfCorners = 4;
    }

    public override void Draw()
    {
        Console.WriteLine("Draw Rectangle");
    }

    public int NumberOfCorners { get; set; };
} 
Run Code Online (Sandbox Code Playgroud)

然后以下将无法工作,因为Shape-class没有NumberOfCorners-property:

Shape shape = new Rectangle();
Console.WriteLine(shape.NumberOfCorners); //This will cause an error.
Run Code Online (Sandbox Code Playgroud)

但是,具体实例仍然深入到一个Rectangle意义的实例之下,这将起作用:

Console.WriteLine((shape as Rectangle).NumberOfCorners); //This is fine, provided that shape is not null.
Run Code Online (Sandbox Code Playgroud)