C# - 关键字用法虚拟+覆盖与新

i3e*_*ays 201 c# syntax overriding method-hiding member-hiding

在基类型" virtual"中声明方法然后使用" override"关键字在子类型中覆盖它而不是new在声明子类型中的匹配方法时简单地使用" "关键字之间有什么区别?

Ori*_*rds 224

我总是通过图片更容易理解这样的事情:

再次,采取约瑟夫戴格尔的代码,

public class Foo
{
     public /*virtual*/ bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public /*override or new*/ bool DoSomething() { return true; }
}
Run Code Online (Sandbox Code Playgroud)

如果你然后调用这样的代码:

Foo a = new Bar();
a.DoSomething();
Run Code Online (Sandbox Code Playgroud)

注意:重要的是我们的对象实际上是a Bar,但是我们将它存储在一个类型的变量中Foo(这类似于转换它)

然后结果将如下,具体取决于您是否使用virtual/ overridenew何时声明您的类.

虚拟/覆盖说明图像

  • 真正努力回答这个问题. (6认同)
  • 谢谢......但是你可以解释一下上面关于你说的铸造的图片吗? (3认同)

alb*_*ein 180

"new"关键字不会覆盖,它表示与基类方法无关的新方法.

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

public class Test
{
    public static void Main ()
    {
        Foo test = new Bar ();
        Console.WriteLine (test.DoSomething ());
    }
}
Run Code Online (Sandbox Code Playgroud)

这打印为false,如果你使用了override,它会打印为true.

(基本代码取自Joseph Daigle)

所以,如果你正在做真正的多态性,你应该总是过度.您需要使用"new"的唯一地方是该方法与基类版本无关.


Fra*_*nov 42

以下是一些用于理解虚拟和非虚拟方法行为差异的代码:

class A
{
    public void foo()
    {
        Console.WriteLine("A::foo()");
    }
    public virtual void bar()
    {
        Console.WriteLine("A::bar()");
    }
}

class B : A
{
    public new void foo()
    {
        Console.WriteLine("B::foo()");
    }
    public override void bar()
    {
        Console.WriteLine("B::bar()");
    }
}

class Program
{
    static int Main(string[] args)
    {
        B b = new B();
        A a = b;
        a.foo(); // Prints A::foo
        b.foo(); // Prints B::foo
        a.bar(); // Prints B::bar
        b.bar(); // Prints B::bar
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我不认为它是为了防止基类被覆盖而创建的。我认为它是为了避免名称冲突而创建的,因为您无法覆盖不是“虚拟”的方法,并且编译器如果在没有“虚拟”签名的“血统”类上看到相同的函数名称,则会抱怨 (2认同)
  • 这是一个非常好的答案。因此,“new”基本上允许父方法保持可访问性(当子方法被强制转换/用作父类型时)。相反,virtual+override 保证使用子方法,无论子方法如何转换/使用(当然,只有重写时)。 (2认同)

Jos*_*gle 19

new关键字实际上创建了一个仅存在于该特定类型上的全新成员.

例如

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}
Run Code Online (Sandbox Code Playgroud)

该方法存在于两种类型中.当您使用反射并获取类型的成员时Bar,您实际上会发现两个DoSomething()看起来完全相同的方法.通过使用new您有效地隐藏基类中的实现,以便当类派生自Bar(在我的示例中)方法调用base.DoSomething()转到Bar而不是Foo.


Wed*_*dge 9

virtual/override告诉编译器这两个方法是相关的,并且在某些情况下,当您认为调用第一个(虚拟)方法时,实际上调用第二个(重写)方法是正确的.这是多态性的基础.

(new SubClass() as BaseClass).VirtualFoo()
Run Code Online (Sandbox Code Playgroud)

将调用SubClass的覆盖VirtualFoo()方法.

new告诉编译器您要将方法添加到与基类中的方法同名的派生类,但它们彼此没有关系.

(new SubClass() as BaseClass).NewBar()
Run Code Online (Sandbox Code Playgroud)

将调用BaseClass的NewBar()方法,而:

(new SubClass()).NewBar()
Run Code Online (Sandbox Code Playgroud)

将调用SubClass的NewBar()方法.


tva*_*son 8

除了技术细节之外,我认为使用虚拟/覆盖可以在设计上传达大量语义信息.声明方法虚拟时,表明您希望实现类可能希望提供自己的非默认实现.同样地,在基类中省略这一点,声明期望默认方法应该足以满足所有实现类.类似地,可以使用抽象声明来强制实现类来提供自己的实现.同样,我认为这传达了很多关于程序员如何期望使用代码的信息.如果我正在编写基础和实现类,并发现自己使用新的,我会认真地重新考虑不要在父级中使方法虚拟并明确声明我的意图的决定.