C#design:为什么抽象方法需要new/override,虚拟方法不需要?

dri*_*iAn 13 c# virtual language-design abstract-methods

为什么抽象方法需要new/override,虚拟方法不需要?

样本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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

样本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;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过默认隐藏方法,这将编译正常.

我完全理解技术差异.但我想知道为什么语言是这样设计的."样本2"中的限制也不是更好吗?我的意思是在大多数情况下,如果你创建一个与父类同名的方法,你通常打算覆盖它.所以我认为明确说明Override/New对虚拟方法也有意义.

这种行为有设计明智的原因吗?

更新: 第二个样本实际上会发出警告.第一个示例显示错误,因为子类是实现抽象方法所必需的.我没有看到VS中的警告..现在对我来说非常有意义.谢谢.

Gre*_*ech 11

使用.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()'.要使当前成员覆盖该实现,请添加override关键字.否则添加新关键字.

在第一种情况下,它是一个错误,因为您实际上并没有覆盖基本方法,这意味着在具体类中没有实现抽象方法.在第二种情况下,它是一个警告,因为代码在技术上是正确的,但编译器怀疑它不是你的意思.这是启用"将警告视为错误"编译设置通常是个好主意的原因之一.

所以我不能重复你的行为,编译器的行为对我来说是正确的.您使用的是哪个版本的编译器?


Eni*_*ity 7

以下是C#规范的答案.

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

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}
Run Code Online (Sandbox Code Playgroud)

衍生中的F声明会导致报告警告.隐藏继承的名称特别不是错误,因为这将排除基类的单独演变.例如,上述情况可能是因为更高版本的Base引入了一个F方法,该方法在该类的早期版本中不存在.如果上述情况是错误,那么对单独版本化类库中的基类所做的任何更改都可能导致派生类变为无效.隐藏继承名称引起的警告可以通过使用new修饰符来消除:

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}
Run Code Online (Sandbox Code Playgroud)

new修饰符指示Derived中的F是"new",并且它确实旨在隐藏继承的成员.