非虚方法和密封方法有什么区别?

时间:2014-02-26 15:30:27

标签: c#

我有一个混乱我想解决..在C#中,只有virtual标记的基类方法可以在派生类中被覆盖。不能覆盖没有virtual标记的基类方法。最好的情况是,派生类可以使用new隐藏基类方法。然后我们有sealed个方法,这些方法也不能在基类中重写。

那么,密封方法和标准非虚方法有什么区别?

另一个相关问题。可以使用sealed

在派生类中替换基类new方法

4 个答案:

答案 0 :(得分:12)

sealed可防止进一步覆盖链上的虚拟方法。您只能在覆盖的方法上定义sealed。请查看sealedhttp://msdn.microsoft.com/en-us/library/aa645769(v=vs.71).aspx

的文档

他们给出了密封使用的一个很好的例子:

using System;
class A
{
   public virtual void F() {
      Console.WriteLine("A.F");
   }
   public virtual void G() {
      Console.WriteLine("A.G");
   }
}
class B: A
{
   sealed override public void F() {
      Console.WriteLine("B.F");
   } 
   override public void G() {
      Console.WriteLine("B.G");
   } 
}
class C: B
{
   override public void G() {
      Console.WriteLine("C.G");
   } 
}

在这种情况下,任何源自B的人都可以覆盖G,但不能覆盖F

答案 1 :(得分:2)

如果我正确阅读this,则密封可以阻止虚拟虚拟。基本上撤消虚拟。

答案 2 :(得分:2)

密封方法只能是覆盖基类方法的方法,因此不能进一步覆盖。

来自文档:

  

当实例方法声明包含一个密封修饰符时,即   方法据说是一种密封方法   如果是实例方法   声明包括密封修饰符,它还必须包括   覆盖修饰符。

虚拟方法不需要这样做。

答案 3 :(得分:0)

原始海报问了两个不同的问题:

  1. sealed方法和标准非虚拟方法之间有什么区别?
  2. 可以使用sealed在派生类中替换基类new方法吗?

问题1-sealed与非虚拟方法之间的区别

如果您不希望子类能够访问要添加的新方法,则创建非虚拟方法是理想的解决方案。例如,您可以向不在其父类中的类添加非虚拟方法。

但是,有时您的班级的父类将方法定义为virtual,但是您不希望班级的任何子级都能够覆盖此方法的特定override。这是您使用sealed的时候。它告诉编译器不再可以覆盖一次virtual方法。请参阅sealed here上的文档。

问题2-是否可以使用sealed替换基类new的方法

是的,他们可以,尽管这可能无法实现您的想法。替换sealed方法的确意味着现在调用该方法将调用您的实现。但是,如果您的类曾经转换为对父类的引用,则将使用该方法的父类实现,而不是您的方法。 Microsoft文档对此here进行了说明。

下面的示例与Microsoft的文档略有修改:

public class A
{
    public virtual void DoWork() { Console.WriteLine("A"); }
}

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

public class C : B
{
    public sealed override void DoWork() { Console.WriteLine("C"); }
}

public class D : C
{
    // Uncommenting the following line would cause a compilation error, since DoWork is sealed
    // public override void DoWork() { Console.WriteLine("D"); }
    
    public new void DoWork() {  Console.WriteLine("D"); }
}

...

// Later on in a class
D d = new D();
d.DoWork(); // Prints "D"

C c = d;
c.DoWork(); // Prints "C"