web-dev-qa-db-ja.com

インターフェイスメンバーを保護できないのはなぜですか?

インターフェイスで保護されたアクセスメンバーを宣言することに対する議論は何ですか?たとえば、これは無効です。

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; 
    ...
}

(確かに、これはstructsでは機能しません)

インターフェイスでprivateまたはinternal修飾子の多くのケースを見ることはできませんが、publicprotected修飾子の両方をサポートすることは完全に合理的です。


protectedsを完全に分離することで、interfaces上のinterfaceメンバーのユーティリティを説明してみましょう。

継承コントラクトを実施するための新しいC#キーワードsupportを想像して、次のように宣言します。

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

これにより、クラスをコントラクトして、保護されたメンバーを継承者に提供できます。

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メンバーを提供することを要求します。これは現在のところ実行できません。

66
ajlane

誰もが、実装の詳細を持たないパブリックメンバーのみを持つインターフェイスのポイントを打ち出したと思います。探しているのは abstract class です。

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がある場合、SeedsプロテクトメソッドではなくIOrangeのみを実装できると主張するのは当然です。それは結構です。定義によるインターフェースは、クラスとそのサブクラス間のものではなく、呼び出し元とオブジェクト間の契約です。抽象クラスは、この概念に近づいています。そしてそれは結構です。基本的に提案しているのは、ビルドを壊すことなくサブクラスをある基本クラスから別の基本クラスに切り替えることができる言語の別の構成体です。私には、これは意味がありません。

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

公正な質問があると思いますが、それはコーナーケースのようであり、正直なところそれから利益が得られるとは思いません。

57
Szymon Rozga

なぜこれが必要なのかわかりません。派生クラスで特定のメソッドの実装を提供する場合は、抽象基本クラスに進みます。インターフェースはまさにそれです-インターフェース。公共の契約、他に何もない。実装が外の世界にどのように見えるべきかを記述する仕様のようなインターフェースを考えてください。 2ピンプラグの仕様には、内部構造がどのようなものである必要があるかは記載されていません(少なくとも私はそう思っています)。プラグソケットとのインターフェイス互換性が必要です。 Plug
(ソース: made-in-china.com

48
Anton Gogolev

意味がないからです。インターフェイスは、公開された契約です。私はIThingなので、求められたらIThingの方法を実行します。 IThingに、説明できない方法を実行することを確認するよう依頼することはできません。

15
annakata

具体的な実装が何であるかを知らなくても、人々がクラスにアクセスできるようにするインターフェースが存在します。これは、データ受け渡し契約から実装を完全に切り離します。

したがって、インターフェイス内のすべてがパブリックでなければなりません。非パブリックメンバーは、実装にアクセスできるため、インターフェイス定義に有意義な貢献をしない場合にのみ役立ちます。

9
JaredPar

インターフェイスメンバーareパブリックAPI。 protectedなどのようなものは実装の詳細です-そして、インターフェースはhave実装ではありません。あなたが探しているのは明示的なインターフェースの実装だと思います:

public class NavelOrange : IOrange
{
    public OrangePeel Peel { get { return new OrangePeel(); } }
    OrangePips IOrange.Seeds { get { return null; } }
}
7
Marc Gravell

インターフェイスは、クライアントに特定の機能を約束する契約です。言い換えれば、インターフェイスの目的は、型をそれにキャストし、そのインターフェイスで保証された機能を必要とするコードにそのように渡すことができるようにすることです。型のクライアントコードはその型の保護されたメンバーにアクセスできないため、インターフェイスで保護されたアイテムを宣言することは意味がありません。

1

インターフェースは、キーの形状に似ています

enter image description here

それは鍵ではありません。

ロックではありません。

これは単なるスリムな接点です。

このため、インターフェースのすべてのメンバー(キーの形状を定義する)はパブリックでなければなりません。

キーがロックを開くには、両者が同じ形状を共有することが重要です。

形状(インターフェース)publicを作成することにより、他のユーザーに互換性のあるロックまたは互換性のあるキーを作成させることができます。

それ以外の場合、(インターフェース)internalにすると、他のユーザーが互換性のあるロックまたは互換性のあるキーを作成できなくなります。

1
Marco Staffoli

インターフェースとは特定のオブジェクトができることのすべてであるため、そのインターフェースを実装するクラスを使用する場合、開発者はすべてのメンバーが実装されることを期待するため、保護されたアクセス修飾子はインターフェースには何も意味しません。

0
Gerrie Schenck

インターフェイスにはパブリックメンバーのみが含まれます。保護されているとは、宣言しているものはすべて、クラスと派生クラスのインスタンスでのみ使用できることを意味します。

0
Jason Punyon

インターフェイスの現在の設計には、実装者に柔軟性を提供するという健全な判断があります。多くの場合、インターフェイスはフレームワークプログラマーによって作成され、実装者は異なる人々であることを忘れないでください。実装を強制することは不必要に厳しいでしょう。

0

インターフェイスを実装することにより、タイプは特定のメソッドセットをサポートすることを示します。これらのメソッドのいずれかが公開されていない場合、呼び出し元は利用できず、そのため、このタイプは前述のインターフェースをサポートしません。

0
Brian Rasmussen

.netインターフェイスを実装するクラスには、すべてのインターフェイスメンバーの実装を含める必要があります。さらに、どのクラスでも、任意のメンバーを派生クラスに公開できます。インターフェースの実装には、派生クラスからのみ使用可能なメンバーを含める必要があることを要求します。(1)そのようなメンバーがインターフェースの外側に見える場合、または(2)インターフェースの実装が使用できない場合、自分で定義しなかったメンバー。インターフェースにネストされたクラス(インターフェースのprotectedメンバーにアクセスできる)を含めることが許可されている場合、protectedインターフェースメンバーは意味があります。実際、インターフェイス内にネストされたクラスがそのインターフェイスの拡張メソッドを定義できる場合、それらは非常に便利です。残念ながら、そのような機能は存在しません。

ところで、インターフェイスでクラスをネストできなくても、インターフェイスメンバーにinternalアクセス修飾子を適用すると、インターフェイスが定義されているアセンブリのみがすべてを定義できるという効果があります。それの実装。

0
supercat