C# 设计:为什么抽象方法需要 new/override 而虚拟方法不需要?

发布于 2024-09-16 19:55:42 字数 924 浏览 6 评论 0原文

为什么抽象方法需要 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;
    }
}

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

示例 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”中也有相同的限制不是更好吗?我的意思是,在大多数情况下,如果您创建一个与父类中同名的方法,您通常会打算覆盖它。因此,我认为明确声明 Override/New 对虚拟方法也有意义。

这种行为有设计方面的原因吗?

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

Why is new/override required on abstract methods but not on virtual methods?

Sample 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;
    }
}

The compiler will show this error:
To make the current member override that implementation, add the override keyword. Otherwise add the new keyword

Sample 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;
    }
}

This will compile fine, by hiding the method by default.

I fully understand the technical differences. However I wonder why the language was designed that way. Wouldn't it be better to have the same restriction in "Sample 2" as well? I mean in most cases if you create a method with the same name as in the parent class, you usually intent to override it. So I think explicitly stating Override/New would make sense on virtual methods as well.

Is there a design-wise reason for this behavior?

Update:
The 2nd sample actually causes a warning. The first sample shows an error because the subclass is required to implement the abstract method. I didn't see the warning in VS.. makes perfectly sense to me now. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

素食主义者 2024-09-23 19:55:42

使用 .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 关键字。否则添加新关键字。

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

所以我无法重现你的行为,并且编译器的行为对我来说看起来是正确的。您使用哪个版本的编译器?

Using either the C# 3.0 compiler as shipped in .NET 3.5 SP1, or the C# 4.0 compiler as shipped in .NET 4.0, I get the following error for your first example:

error CS0534: 'ConsoleApplication3.Square' does not implement inherited abstract member 'ConsoleApplication3.ShapesClass.Area()'

And the following warning for the second one:

warning CS0114: 'ConsoleApplication3.Square.Area()' hides inherited member 'ConsoleApplication3.ShapesClass.Area()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

In the first case it's an error because you aren't actually overriding the base method, which means there is no implementation for the abstract method in a concrete class. In the second case it's a warning because the code is technically correct, but the compiler suspects that it isn't what you meant. This is one of the reasons it's generally a good idea to enable the "treat warnings as errors" compilation setting.

So I can't repro your behaviour, and the behaviour of the compiler looks right to me. Which version of the compiler are you using?

蓝眸 2024-09-23 19:55:42

这是直接来自 C# 规范的答案。

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

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

派生原因中 F 的声明
要报告的警告。隐藏一个
继承的名称特别不是
错误,因为这会排除
基类的单独演化。
例如,上述情况可能
之所以发生是因为后来
Base版本引入了F方法
这在之前的版本中是不存在的
类的版本。有以上情况的
情况是一个错误,那么任何
对 a 中的基类进行的更改
单独版本化的类库
可能会导致派生
类变得无效。警告
由于隐藏继承的名称而导致
通过使用新的
修饰符:

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

新修饰符表示 F
在 Derived 中是“新的”,并且它是
确实是想隐藏继承的
会员。

Here's the answer straight from the C# spec.

...hiding an accessible name from an
inherited scope causes a warning to be
reported. In the example

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

the declaration of F in Derived causes
a warning to be reported. Hiding an
inherited name is specifically not an
error, since that would preclude
separate evolution of base classes.
For example, the above situation might
have come about because a later
version of Base introduced an F method
that wasn’t present in an earlier
version of the class. Had the above
situation been an error, then any
change made to a base class in a
separately versioned class library
could potentially cause derived
classes to become invalid. The warning
caused by hiding an inherited name can
be eliminated through use of the new
modifier:

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

The new modifier indicates that the F
in Derived is “new”, and that it is
indeed intended to hide the inherited
member.

叶落知秋 2024-09-23 19:55:42

不同之处在于抽象方法必须被重写,而虚拟方法则不需要。

继承抽象类(在非抽象类中)而不实现所有抽象成员是错误的,但只有在从类继承而不指定 overridenew 时才会收到警告code> 为虚方法。

The difference is that the abstract method has to be overridden, but the virtual doesn't.

It's an error to inherit the abstract class (in a non-abstract class) without implementing all abstract members, but you only get a warning when inheriting from the class without specifying override or new for the virtual method.

惯饮孤独 2024-09-23 19:55:42

版本控制

乍一看,您可能会认为方法隐藏似乎不是特别有用。有一种情况
但是,您可能需要使用它的地方。假设您想使用一个名为 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() 方法会导致问题:
Car 类中的 Accelerate() 方法隐藏了现在定义的继承的 Accelerate() 方法
他们的 MotorVehicle 类。稍后,当您编译 Car 类时,编译器并不清楚
您是否确实希望您的方法隐藏继承的方法。正因为如此,
当您尝试编译 Car 类时,编译器会报告以下警告:

警告 CS0114:“Car.Accelerate()”隐藏继承成员
'MotorVehicle.Accelerate()'。使当前成员覆盖该成员
实现时,添加 override 关键字。否则添加新关键字。

Versioning

At first glance, you may think that method hiding doesn’t appear particularly useful. There is a situation
where you might need to use it, however. Let’s say you want to use a class named MotorVehicle that
was written by another programmer, and you want to use this class to derive your own class. Further,
let’s also assume you want to define an Accelerate() method in your derived class. For example:

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

Next, let’s suppose that the other programmer later modifies the MotorVehicle class and decides
to add her own virtual Accelerate() method:

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

The addition of this Accelerate() method by the other programmer causes a problem: The
Accelerate() method in your Car class hides the inherited Accelerate() method now defined in
their MotorVehicle class. Later, when you come to compile your Car class, it isn’t clear to the compiler
whether you actually intended your method to hide the inherited method. Because of this, the
compiler reports the following warning when you try to compile your Car class:

warning CS0114: ‘Car.Accelerate()’ hides inherited member
‘MotorVehicle.Accelerate()’. To make the current member override that
implementation, add the override keyword. Otherwise add the new keyword.

浅黛梨妆こ 2024-09-23 19:55:42

我认为在第一种方式中你会得到编译器错误,因为抽象方法是隐藏的并且没有实现(所以实际上你的类是错误的,并且很难找出原因)。在第二种情况下,您只会收到警告,因为该类可用。

I think in the first way you get the compiler error, because the abstract method is hidden and not implemented (so effectively your class is wrong, and it would be difficult to figure out why). In the second case you get only a warning, because the class is usable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文