1. ホーム
  2. c#

[解決済み] なぜprotectedインターフェイスのメンバを持つことができないのですか?

2023-07-27 16:37:23

質問

インターフェイスで protected-access のメンバを宣言することに対する反論は? 例えばこれは無効です。

public interface IOrange
{
    public OrangePeel Peel { get; }
    protected OrangePips Seeds { get; }
}

この例では、インターフェイス IOrange は、実装者が 少なくとも を提供します。 OrangePips インスタンスを提供します。もし実装者が望むなら、スコープを完全な public :

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    public OrangePips Seeds { get { return new OrangePips(6); } }
}

の意図は protected メンバのサポート契約を提供することです。 継承者 (サブクラス) などのサポート契約を提供することです。

public class SpecialNavelOrange : NavelOrange
{
    ...
    // Having a seed value is useful to me.
    OrangePips seeds = this.Seeds; 
    ...
}

(確かに、これは struct s)

のケースはあまり見当たりません。 private または internal 修飾子の両方をサポートしていますが publicprotected 修飾子は完全に合理的であると思われます。


の有用性を説明してみようと思います。 protected のメンバーについて interface から切り離すことで interface を完全に分離することです。

新しいC#のキーワードを想像してみましょう。 support という、継承者の契約を強制するためのキーワードを用意し、以下のように宣言するようにします。

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

これにより、クラスを契約して、継承者にprotectedなメンバを提供することができるようになります。

public class NavelOrange : IOrange, IOrangeSupport
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    protected OrangePips Seeds { get { return null; } }
}

これは特に有用ではありません。なぜなら、クラスはすでに protected メンバを提供することによって、この契約をすでに暗示しているからです。

でも、それならこうもできる。

public interface IOrange : IOrangeSupport
{
   ...
}

これにより IOrangeSupport を実装する全てのクラスに IOrange を実装し、特定の protected メンバを提供することを要求する - これは現在私たちができることではありません。

どのように解決するのですか?

インターフェイスは公開メンバーのみを持ち、実装の詳細を持たないという点は、誰もが打ち明けたことだと思います。あなたが探しているものは 抽象クラス .

public interface IOrange
{
    OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
    protected OrangeBase() {}
    protected abstract OrangePips Seeds { get; }
    public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
    public override OrangePeel Peel { get { return new OrangePeel(); } }
    protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

編集:Ornamentクラスから派生したPlasticOrangeがあったとして、それはIOrangeしか実装できず、Seedsのprotectedメソッドは実装できないという主張は妥当でしょう。それはそれでいいのです。インターフェイスの定義は、呼び出し側とオブジェクトの間の契約であって、クラスとそのサブクラスの間の契約ではありません。抽象クラスは、この概念に限りなく近い。そして、それはそれでいいのです。あなたが本質的に提案しているのは、あるベースクラスから別のベースクラスへ、ビルドを壊さずにサブクラスを切り替えることができる、言語の別の構成です。私にとっては、これは意味を成しません。

クラスのサブクラスを作成する場合、そのサブクラスはベースクラスの特殊化です。それは、ベース クラスの任意の保護されたメンバーを完全に認識する必要があります。しかし、突然ベースクラスを切り替えたい場合、サブクラスが他のIOrangeで動作しなければならないのは意味がありません。

正しい質問だと思いますが、コーナーケースのようで、正直なところ何のメリットも見出せません。