2010-11-11 54 views
26

我是C#中的一个新手。我正在阅读有关密封关键字。我有关于密封类。我读了一个关于密封方法的行,我们可以使密封方法也行。行是(由声明方法为密封,我们可以避免进一步重写此方法。) 我创建了一个演示,但不明白上面的行和密封方法使用的含义。以下是我的代码: -C#中的密封方法#

using System; 

namespace ConsoleApplication2 
{ 
    class Program:MyClass 
    { 
     public override sealed void Test() 
     { 
      Console.WriteLine("My class Program"); 
     } 
     static void Main(string[] args) 
     { 
      Program obj = new Program(); 
      obj.Test(); 
      Console.ReadLine(); 
     } 
    } 

    class MyClass 
    { 
     public virtual void Test() 
     { 
      Console.WriteLine("My class Test"); 
     } 
    } 


} 

请告诉我为什么我们使用密封方法以及密封方法的优点是什么。

回答

48

那么,你正在测试只有两个级别的继承,而且你没有意识到你正在“进一步压倒”一个方法。如果你把它三,你可以看到什么呢sealed

class Base { 
    public virtual void Test() { ... } 
} 
class Subclass1 : Base { 
    public sealed override void Test() { ... } 
} 
class Subclass2 : Subclass1 { 
    public override void Test() { ... } // Does not compile! 
    // If `Subclass1.Test` was not sealed, it would've compiled correctly. 
} 
+0

谢谢Mehrdad .. :) – 2010-11-11 07:17:55

+0

我能做到这一点与第一级是一个接口? – 2015-04-17 04:02:38

-3

C#有它,因为Java具有相同的功能(final方法)。我从来没有见过合法的用途。

如果你不想允许扩展,整个班级应该被标记为sealed而不只是一种方法。

+6

C#有它,因为Java有它?我不这么认为。更可能的解释是C#和Java都具有该功能,因为它是一个有用的功能。 – 2010-11-11 07:12:12

+2

@Eric:当然,如果我们正在谈论数组协变,这将是一个不同的问题;) – 2010-11-11 07:25:30

+0

@Jon:事实上,尽管设计决策链当然有点不直接。我会说CLR类型系统具有该功能,因为Java语言确实具有该功能,而C#具有该功能,因为CLR类型系统具有该功能。 – 2010-11-11 15:55:00

18

好吧,你只用在方法“密封”如果你不希望任何派生类进一步重写你的方法。如果方法没有被声明为虚拟的,并且不覆盖另一个虚拟方法,那么方法将被默认密封。 (在Java中,方法默认是虚拟的 - 要实现默认的C#行为,您必须将方法标记为final。)

我个人喜欢仔细控制继承 - 我喜欢整个类在可能的情况下进行密封。但是,在某些情况下,您仍然希望允许继承,但请确保某些方法不会被进一步覆盖。一种用途可能是有效地template the method,例如用于诊断:

public sealed override void Foo(int x) 
{ 
    Log("Foo called with argument: {0}", x); 
    FooImpl(x); 
    Log("Foo completed"); 
} 

protected abstract void FooImpl(int x); 

现在,子类不能直接覆盖Foo - 他们不得不重写FooImpl,所以我们的行为将始终当其他代码调用Foo执行。

模板可能是出于其他原因当然 - 例如强制参数验证的某些方面。

根据我的经验,密封方法并不经常使用,但我很高兴能力在那里。 (我只是希望课程默认是封闭的,但那是另一次对话。)

58

一个密封是不能作为基类另一个更派生类中的一个。

一个密封的方法在一个未密封的类中是一个方法,它不能在这个类的派生类中重写。

为什么我们使用密封方法?密封方法的优点是什么?

那么,为什么你使用虚拟方法呢? 提供一个点,在该点可以定制一个类的行为。那么为什么你使用密封方法? 提供一个点,在这一点上,您可以保证在任何派生类的行为方面不会发生进一步的变化

可以自定义类的行为的点是有用但是危险。它们很有用,因为它们使派生类能够更改基类的行为。它们很危险......等待它...... ,因为它们使派生类能够改变基类的行为。虚拟方法基本上允许第三方让你的课程疯狂你从未预期或测试过的东西。

我喜欢编写符合我预期和测试的代码。密封方法允许您继续允许部分类被覆盖,同时使密封的方法具有可保证的,可测试的,稳定的行为,这些行为不能进一步定制。

+0

谢谢Eric .. :) – 2010-11-11 07:16:42

+0

+1谢谢,很好的答案。 – Sabuncu 2014-05-28 17:49:38

+0

谢谢@Eric。简单和详细的解释。 – Slan 2016-12-05 07:37:42

1

现在,如果你申报计划的一个子类,你将无法覆盖的测试方法,这就是问题所在。

在大多数情况下,你将不再需要密封的方法,但他们可以证明自己有用的,当你正在开发的第三方开发者,以便创建自己的插件扩展一些插件系统的基类。您可以保留一些服务数据,如插件名称以及是否启用,并使用密封的方法和属性来完成它,因此插件开发人员不会搞砸它。这是一种情况下,当密封部件来方便

1

密封方法

密封方法被用来定义一个虚拟方法的首要水平。

密封关键字始终与覆盖关键字一起使用。

密封方法的实际演示

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace sealed_method 
{ 
    class Program 
    { 
     public class BaseClass 
     { 

      public virtual void Display() 
      { 
       Console.WriteLine("Virtual method"); 
      } 
     } 

     public class DerivedClass : BaseClass 
     { 
      // Now the display method have been sealed and can;t be overridden 
      public override sealed void Display() 
      { 
       Console.WriteLine("Sealed method"); 
      } 
     } 

     //public class ThirdClass : DerivedClass 
     //{ 

     // public override void Display() 
     // { 
     //  Console.WriteLine("Here we try again to override display method which is not possible and will give error"); 
     // } 
     //} 

     static void Main(string[] args) 
     { 

      DerivedClass ob1 = new DerivedClass(); 
      ob1.Display(); 

      Console.ReadLine(); 
     } 
    } 
}