C#设计:为什么在抽象方法上需要新的/覆盖,而在虚拟方法上不需要新的/替代?

StackOverflow https://stackoverflow.com/questions/3634529

为什么在抽象方法上需要新的/替代,而在虚拟方法上不需要新的?

样本1:

abstract class ShapesClass
{
    abstract public int Area(); // abstract!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // Error: missing 'override' or 'new'
    {
        return x * y;
    }
}

编译器将显示此错误:要使当前成员覆盖该实现,请添加覆盖关键字。否则添加新关键字

样本2:

class ShapesClass
{
    virtual public int Area() { return 0; } // it is virtual now!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // no explicit 'override' or 'new' required
    {
        return x * y;
    }
}

默认情况下隐藏该方法,这将罚款。

我完全了解技术差异。但是,我想知道为什么该语言是这样设计的。在“样本2”中拥有相同的限制会更好吗?我的意思是,在大多数情况下,如果您创建了一种与父母类别相同的名称的方法,则通常打算覆盖它。因此,我认为明确说明覆盖/新的方法也将在虚拟方法上也有意义。

这种行为是否有设计理由?

更新:第二个样本实际上会引起警告。第一个示例显示错误,因为需要子类以实现抽象方法。我没有看到VS中的警告。现在对我来说很有意义。谢谢。

有帮助吗?

解决方案

在.NET 3.5 SP1中使用C#3.0编译器,或者在.NET 4.0中发货的C#4.0编译器,我将获得以下内容 错误 对于您的第一个示例:

错误CS0534:“ consoleapplication3.square”不实现继承的抽象成员'consoleapplication3.shapesclass.area()'

和以下内容 警告 第二个:

警告CS0114:“ consoleapplication3.square.area()'隐藏成员'consoleapplication3.shapesclass.area()'。要使当前成员覆盖该实现,请添加覆盖关键字。否则添加新关键字。

在第一种情况下,这是一个错误,因为您实际上没有覆盖基本方法,这意味着在混凝土类中没有针对抽象方法实现。在第二种情况下,这是一个警告,因为代码在技术上是正确的,但是编译器怀疑这不是您的意思。这是通常一个好主意的原因之一,可以使“将警告视为错误”汇编设置。

因此,我无法再现您的行为,编译器的行为对我来说是正确的。您正在使用哪个版本的编译器?

其他提示

这是C#规格的直接答案。

...从继承的范围内隐藏一个可访问的名称会导致警告报告。在示例中

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}

派生中F的声明会导致警告报告。隐藏继承的名称不是特别的错误,因为这将排除基类别的单独演变。例如,上述情况可能发生了,因为较晚版本的基础引入了f方法中不存在的F方法。如果上述情况是错误的,那么在单独版的类库中对基类进行的任何更改都可能导致派生类变得无效。隐藏继承名称引起的警告可以通过使用新修饰符来消除:

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}

新的修饰符表明派生的F是“新”,并且确实旨在隐藏继承的成员。

不同之处在于,抽象方法必须被覆盖,但虚拟方法却没有。

在不实施所有抽象成员的情况下继承抽象类(在非抽取类中)是错误 override 或者 new 对于虚拟方法。

我认为以第一个方式获得编译器错误,因为抽象方法被隐藏并且没有实现(因此,您的类是错误的,因此很难弄清楚原因)。在第二种情况下,您只会收到警告,因为课程可用。

版本控制

乍一看,您可能会认为隐藏方法似乎并不特别有用。但是,在某些情况下,您可能需要使用它。假设您想使用名为的课程 MotorVehicle 这是由另一个程序员撰写的,您想使用此课程来得出自己的课程。此外,我们还假设您要定义一个 Accelerate() 您的派生类中的方法。例如:

public class Car : MotorVehicle
{
    // define the Accelerate() method
    public void Accelerate()
    {
        Console.WriteLine(“In Car Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

接下来,假设其他程序员后来修改了Motorvehicle类,并决定添加自己的 virtual Accelerate() 方法:

public class MotorVehicle
{
    // define the Accelerate() method
    public virtual void Accelerate()
    {
        Console.WriteLine(“In MotorVehicle Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

加法 Accelerate() 其他程序员的方法引起了问题:Accelerate() 您的方法 Car 班级隐藏继承 Accelerate() 现在在他们的 MotorVehicle 班级。后来,当您来编译您的 Car 课堂,编译器尚不清楚您是否真正打算隐藏继承方法的方法。因此,编译器在尝试编译汽车课时报告以下警告:

警告CS0114:'car.accelerate()'隐藏成员'MotorVehicle.accelerate()'。要使当前成员覆盖该实现,请添加覆盖关键字。否则添加新关键字。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top