2010-11-11 56 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(); 
     } 
    } 
}