25

如何防止方法在派生类中被覆盖?

在 Java 中,我可以通过在final我希望防止被覆盖的方法上使用修饰符来做到这一点。

如何在 C# 中实现相同的目标?
我知道使用sealed但显然我只能将它与override关键字一起使用?

class A
{
    public void methodA()
    {
        // Code.
    }

    public virtual void methodB()
    {
        // Code.
    }
}

class B : A
{
    sealed override public void methodB()
    {
        // Code.
    } 
}

所以在上面的例子中,我可以防止methodB()被任何派生自 class 的类覆盖B,但是我如何首先防止 classB覆盖methodB()

更新:当我发布这个问题时,我错过了A 类声明virtual中的关键字。methodB()更正了它。

4

4 回答 4

31

你不需要做任何事情。virtual修饰符指定方法可以被覆盖。省略它意味着该方法是“最终的”。

具体来说,方法必须是virtualabstractoverride,才能被覆盖。

使用new关键字将允许隐藏基类方法,但它仍然不会覆盖它,即当您调用时,A.methodB()您将获得基类版本,但如果您调用B.methodB(),您将获得新版本。

于 2012-03-28T20:14:50.223 回答
28

正如您所提到的,您可以通过使用with来防止在 B 类中进一步覆盖 MethodBsealed override

class B : A
{
    public sealed override void methodB()
    {
        Console.WriteLine("Class C cannot override this method now");
    }
}

使用sealed修饰符以及 override防止派生类进一步覆盖该方法。

如果您不想methodB在 A 类中被任何子类覆盖,请不要标记该方法virtual。只需将其删除。virtual 关键字使方法可以在子类中被覆盖

public void methodA()
{       
}

在您的类上使用sealed关键字以防止进一步覆盖该类

于 2012-03-28T20:12:55.687 回答
7

在 C# 中,未标记的函数virtual(也包括虚函数的覆盖)被有效地密封并且不能被覆盖。因此,您的示例代码实际上不会编译,因为 override 关键字无效,除非在基类中有一个标记为 virtual 且具有相同签名的方法。

如果 A.methodB() 被标记为虚拟,那么您可以覆盖 A 中的方法,但防止它在更间接派生的类中被进一步覆盖,sealed正如您所展示的那样使用关键字。

要记住的一件事是,虽然可以防止方法覆盖,但方法隐藏却不能。鉴于您当前对 A 类的定义,以下对 B 类的定义是合法的,您对此无能为力:

class B:A
 {
      public new void methodB()
            {
                    //code
            } 
  }

new关键字基本上“破坏”了与这一方法相关的继承/覆盖层次结构;对 B 类的任何引用,被视为 B 类(或任何进一步的派生类型)将使用 B 类的实现并忽略 A 类的实现,除非 B 的实现特别回调它。但是,如果您将 B 类的实例视为 A 类(通过强制转换或将其作为参数传递),则“新”实现将被忽略。

这与覆盖不同,其中被视为类 A 并真正覆盖虚拟方法 B 的类 B 仍将使用 B 类对该方法的覆盖。还要了解推断方法隐藏(尽管您会收到编译器警告);如果您在派生类中声明具有相同签名的方法并且未指定 new 或 override,则基类方法将被隐藏。

于 2012-03-28T20:23:55.880 回答
1

在基类中,sealed 关键字仅用于防止派生一个类,但在继承类中,它可用于防止另一个继承类覆盖该方法。

为了防止基类方法被覆盖,只是不要将其指定为虚拟的。在您提供的示例中,类 B 无法覆盖methodB,因为methodB未在原始类上标记为虚拟。

这将编译:

class A
{
    public virtual void methodA()
    {
        //code
    }
    public virtual void methodB()
    {
        //code
    }
}
class B:A
{
    public override void methodB()
    {
        //code
    } 
}

这不会:

class A
{
    public void methodA()
    {
        //code
    }
    public void methodB()
    {
        //code
    }
}
class B:A
{
    public override void methodB()
    {
        //code
    } 
}

编辑:澄清并更正了我关于密封关键字的原始陈述

于 2012-03-28T20:16:22.913 回答