如何防止在派生类中重写方法?
在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()
被派生自类B
的任何类重写,但是如何阻止类B
覆盖methodB()
在第一个地方?
更新:当我发布此问题时,我错过了A类virtual
声明中的methodB()
关键字。纠正了它。
答案 0 :(得分:26)
你不需要做任何事情。 virtual
修饰符指定可以覆盖方法。省略它意味着该方法是'最终'。
具体而言,方法必须为virtual
,abstract
或override
才能覆盖。
使用new
关键字将允许隐藏基类方法,但它仍然不会覆盖它,即当您调用A.methodB()
时,您将获得基类版本,但是如果您调用{ {1}}您将获得新版本。
答案 1 :(得分:17)
正如您所提到的,您可以使用sealed
override
class B : A
{
public sealed override void methodB()
{
Console.WriteLine("Class C cannot override this method now");
}
}
使用sealed
修饰符和 override
可防止派生类进一步覆盖该方法。
如果您不希望A类中的methodB
被任何子类覆盖,请不要标记该方法virtual
。只需删除它。 virtual关键字允许在子类中重写该方法
public void methodA()
{
}
在您的课程中使用sealed
关键字,以防止进一步覆盖课程
答案 2 :(得分:5)
在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,则将隐藏基类方法。
答案 3 :(得分: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
}
}
EDITTED:澄清并更正了我关于密封关键字的原始陈述