关于c#:为什么新的“隐藏”基类方法?


Why does new “hide” the base class method?

我对术语有疑问。根据msdn:"重写修饰符扩展了基类方法,而新修饰符隐藏了它。"但是,在下面的示例中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;

namespace ConsoleApplication2
{
    class BaseClass
    {
        public virtual void Method1()
        {
            Console.WriteLine("Base - Method1");
        }
    }

    class DerivedClass : BaseClass
    {
        public void Method1() // DerivedClass.Method1() hides inherited memeber BaseClass.Method1(). Use the new keyword if hiding was intended.
        {
            Console.WriteLine("Derived - Method1");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            BaseClass bd = new DerivedClass();
            bd.Method1();
            Console.ReadLine();

        }
    }
}

您将看到,如果在派生类中声明method1()时使用new,bd.method1()将按照基类中的说明输出:"base-method1"。

…但是,如果在派生类中声明method1()时使用override,bd.method1()将按照派生类中的说明输出:"derived-method1"。

为什么每个源(包括官方文档)都说new隐藏了基类方法,而在本例中,当使用new时,基类方法显然是调用的方法?

我了解不同的行为(新的行为与替代行为相比),但不了解术语。


方法从基类隐藏方法意味着什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BaseClass
{
    public virtual void Method1()
    {
        Console.WriteLine("Base - Method1");
    }
}

class DerivedClass : BaseClass
{
    public void Method1() // DerivedClass.Method1() hides inherited memeber BaseClass.Method1(). Use the new keyword if hiding was intended.
    {
        Console.WriteLine("Derived - Method1");
    }
}

想象一下如果你写了以下内容:

1
2
var dc = new DerivedClass();
dc.Method1();

编译并运行此代码,然后调用派生方法。但现在,删除BaseClass中的Method1。代码仍然编译并运行完全相同。

DerivedClass中的Method1隐藏了BaseClass中的Method1方法,不让任何直接使用DerivedClass的人使用(或任何进一步派生的实例)。


new有几种用途。您所引用的文档中提到的是声明修饰符。

派生类中的Method1()可以通过三种方式声明:

1
2
3
public void Method1()         // 1
public new void Method1()     // 2
public virtual void Method1() // 3

版本1和2都隐藏了基类中同名的虚方法,因此当对基类变量调用时,将调用BaseClass.Method1()。但是版本2(使用new时)显式地隐藏了基类方法,即您告诉编译器这是有意的。版本1隐式地隐藏了虚方法,并将导致警告,因为编译器假定它可能是意外的,而不是有意的。

隐藏并不意味着你认为它能做什么。这意味着在DerivedClass及其任何后代中,Method1()不再是虚拟的,您不能再对DerivedClass调用虚拟方法。他们说虚拟方法对DerivedClass是隐藏的。这意味着它打破了(继承)多态性。

版本3重写相同名称的方法,如果一个方法是虚拟的,无论变量如何声明,都将调用实际的方法。因此,如果变量声明为BaseClass,但实际上类是DerivedClass,那么将调用派生的方法。

更多信息:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-modifier

请注意,使用EDOCX1[0]与您理解的不同:

1
BaseClass bd = new DerivedClass();

这是不同的new,而不是声明修饰符。


@https://stackoverflow.com/users/8179257/hhdr103-hhdr103使用以下类型实现多态性1.方法过载2.方法重写3、方法隐藏

案例一:如果在派生类中声明method1()时使用new,bd.method1()将按照基类中的说明输出:"base-method1"。答:baseclass bd=new derivedclass();此处根据内存分配实例化派生类并为基类分配地址编译器优先使用基类中的虚方法。如果你的代码变成这样DerivedClass bd=新的DerivedClass();它将调用新方法。案例II:…但是,如果在派生类中声明method1()时使用override,bd.method1()将按照派生类中的说明输出:"derived-method1"。答:baseclass bd=new derivedclass();此处根据内存分配实例化派生类并为基类分配地址控件进入基类并检查虚拟方法。此外,检查虚拟方法是否已被重写。如果被重写,则让它调用被重写的方法。如果未被重写,则它将调用虚拟方法。