2017-10-11 112 views
0

我希望這不是重複的,但我無法通過Google或SO搜索找到。如果我想強制一個方法的重載方法的實現的可訪問性爲protected,是我的唯一選擇,要麼創建爲abstractprotected virtual?我知道接口指定了聲明,但將可訪問性/範圍留給了類實現,但我想確定。子方法的限制範圍

我想知道/確定是否限制方法範圍的唯一方法是通過abstract \ protected virtual給出「這適用於類實現或子覆蓋實現」的語義。

要說明的代碼示例。我知道我可以做到以下幾點,並且像這樣限制實現的範圍;

public class BaseClass 
{ 
    protected virtual void OnlyMeOrChildrenCanDoAction() 
    { 
     // leave empty as current class is structural/conceptual 
     // but child instances may need it 
    } 
} 

通過做上述保證了我的孩子實現只overrideOnlyMeorChildrenCanDoAction()protected但不public可以。

但是,有沒有另一種方法限制到protected而不訴諸於abstractprotected virtual?創建這種方法的示例是Object.Finalize(),如here所示。

或者,爲了稍微反轉問題,爲什麼要創建一個方法爲protected virtual,除非確保任何實現的範圍有限?或者還有另一種方法來做同樣的事情嗎?

+1

我很難理解你想問什麼。我會建議添加一些代碼示例。我不是downvoter,雖然 – maccettura

+0

我仍然很迷路。 – maccettura

+0

@maccettura如果我創建一個方法'保護虛擬'我保證只有子實現可以使用'protected'方法。我不能讓子實現將它覆蓋爲「public」。上述方法是否僅限於此? – DiskJunky

回答

3

我認爲你誤解了virtual的含義和用法。如果聲明爲虛擬,您可以僅在重寫父類中的方法。子類中的重寫方法必須與父類中的方法具有相同的可見性。

在接口中聲明的方法的實現始終爲public

聲明方法abstract與聲明virtual具有相同的效果,除非您沒有在類中實現它,並且從您的類派生的任何具體類必須實現它。

+0

接口實現的範圍由實現者決定,除非實現者聲明(只要我知道),否則不是「public」。這並沒有回答我的問題:是否有另一種限制子實現範圍的方法? – DiskJunky

+1

「要實現接口成員,實現類的相應成員必須是公共的,非靜態的,並且與接口成員具有相同的名稱和簽名。」 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ –

+0

我站好了。這確實回答說,一個界面是不是要走的路 – DiskJunky

2

從技術上講,編譯器不允許在從父級重寫它時更改方法的訪問修飾符,所以問題的答案是通過將方法聲明爲受保護的類內部,可用於派生類(不論是否抽象是一個單獨的問題,也不受訪問級別的限制)。

但請記住,派生類可以自由地以某種其他方式公開該函數,例如從公共方法中調用受保護的方法,並且無法阻止該方法。至於「爲什麼」你有一個受保護的抽象成員,在Template Method模式的許多實現中可以看到一個很好的例子。您可能有一個抽象基類,它描述算法的結構,並將每個步驟邊界內發生的具體步驟留給派生類。在這種情況下,實現的一種方法是將基類聲明爲抽象類型,使用公共方法作爲算法的「入口點」,並將算法中使用的特定方法定義爲受保護的抽象方法,派生類的職責將是。這種模式做了很好的工作,只公開那些有意被世界消費的東西,但是可以從單元測試的角度提出一些挑戰,有時通過提高輔助方法從受保護到內部的可見性來解決這些問題。

+0

我的問題不是圍繞'protected' /'public',而是圍繞給孩子們一種實現功能的方式。也就是說,任何關於「公共」/「受保護」的混淆都可能更多地歸結爲我的問題的糟糕表述,對此,也表示道歉。你的觀點是好的,說得好,只是不是我駕駛的。 – DiskJunky

1

您不能使用c#語言來阻止派生類實現公共版本OnlyMeOrChildrenCanDoAction。即使您將其標記爲protected virtual,派生類也可以使用new關鍵字來覆蓋方法並更改其可訪問性。例如:

public class BaseClass 
{ 
    protected virtual void OnlyMeOrChildrenCanDoAction() 
    { 
     // leave empty as current class is structural/conceptual 
     // but child instances may need it 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    public new void OnlyMeOrChildrenCanDoAction() 
    { 
     Console.WriteLine("This is public."); 
    } 
} 

public class Program 
{ 
    public static void Main() 
    { 
     var b = new BaseClass(); 
     //b.OnlyMeOrChildrenCanDoAction(); //Will not compile 

     var d = new DerivedClass(); 
     d.OnlyMeOrChildrenCanDoAction(); //Look! It's public! 
    } 
} 

輸出:對DotNetFiddle可用

This is public. 

代碼。

如果你想保護呼叫者免受呼叫OnlyMeOrChildrenCanDoAction,你最好的選擇是調用者只使用接口。如果OnlyMeOrChildrenCanDoAction不在接口中,即使派生類決定將其公開爲公共類成員,調用者也無法調用它。無論如何,這是很好的SOLID設計。另一方面,如果你不太擔心調用者,因爲擔心自己的開發團隊做壞事,或許你最好的選擇是使用FxCop或其他一些源代碼規則引擎集成到您的持續構建過程。開發人員仍然可以添加該方法,但是如果他們這樣做,您可以設置一個規則來使其失敗。

+0

問題不在於限制訪問(儘管你的答案是徹底的),它是圍繞着,如果有另一種方式給孩子實現通過除'抽象','接口以外的機制實現功能的選項'或'保護虛擬'。根據迄今爲止的答案,這是一個「不」。我很欣賞這個問題的原因是深奧的,但它主要圍繞着爲什麼'Finalize'被實現。 – DiskJunky