webentwicklung-frage-antwort-db.com.de

Warum kann ich keine Schnittstellenmitglieder geschützt haben?

Was ist das Argument gegen die Deklaration von Mitgliedern mit geschütztem Zugriff auf Schnittstellen? Dies ist beispielsweise ungültig:

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

In diesem Beispiel würde die Schnittstelle IOrange garantieren, dass die Implementierer zumindest ihren Vererbern eine OrangePips-Instanz zur Verfügung stellen. Wenn der Implementierer dies wünschte, könnte er den Geltungsbereich auf public erweitern:

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

Die Absicht von protected Mitgliedern auf Schnittstellen besteht darin, einen Unterstützungsvertrag für Vererbungen (Unterklassen) bereitzustellen, z.

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

(Zugegeben, das würde für structs nicht funktionieren)

Ich kann nicht viel von private- oder internal-Modifizierern in Interfaces sehen, aber die Unterstützung sowohl der public- als auch der protected-Modifizierer erscheint völlig vernünftig.


Ich werde versuchen, den Nutzen von protected-Mitgliedern auf interfaces zu erklären, indem ich sie vollständig von interfaces trenne:

Stellen wir uns ein neues C # -Schlüsselwort support vor, um Vererberverträge durchzusetzen, sodass wir die Dinge wie folgt deklarieren:

public support IOrangeSupport
{
    OrangePips Seeds { get; }
}

Dies würde es uns ermöglichen, Klassen zu beauftragen, um geschützte Mitglieder ihren Erben zur Verfügung zu stellen:

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

Dies ist nicht besonders nützlich, da Klassen diesen Vertrag bereits implizieren würden, indem sie protected-Mitglieder bereitstellen.

Aber dann könnten wir das auch tun:

public interface IOrange : IOrangeSupport
{
   ...
}

Dabei gilt IOrangeSupport für alle Klassen, die IOrange implementieren, und die Angabe bestimmter protected-Member. Dies können wir derzeit nicht tun.

62
ajlane

Ich denke, jeder hat den Punkt einer Schnittstelle gehemmt, die nur öffentliche Mitglieder hat, keine Implementierungsdetails. Was Sie suchen, ist eine abstrakte Klasse

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

Edit: Es ist fair zu argumentieren, dass ein PlasticOrange, das von einer Klasse Ornament abgeleitet ist, nur IOrange und nicht die geschützte Seeds-Methode implementieren kann. Das ist gut. Eine Schnittstelle ist definitionsgemäß ein Vertrag zwischen einem Aufrufer und einem Objekt, nicht zwischen einer Klasse und ihren Unterklassen. Die abstrakte Klasse ist so nah wie wir zu diesem Konzept kommen. Und das ist gut so. Was Sie im Wesentlichen vorschlagen, ist ein anderes Konstrukt in der Sprache, durch das wir Unterklassen von einer Basisklasse zu einer anderen wechseln können, ohne den Build zu beschädigen. Für mich ergibt das keinen Sinn. 

Wenn Sie eine Unterklasse einer Klasse erstellen, ist die Unterklasse eine Spezialisierung der Basisklasse. Sie sollte alle geschützten Mitglieder der Basisklasse vollständig kennen. Wenn Sie jedoch plötzlich die Basisklasse austauschen möchten, macht es keinen Sinn, dass die Unterklasse mit einer anderen IOrange zusammenarbeitet.

Ich nehme an, Sie haben eine faire Frage, aber es scheint ein eckiger Fall zu sein, und ich sehe keinen Nutzen daraus, um ehrlich zu sein.

55
Szymon Rozga

Kann nicht verstehen, warum sollte man das wollen? Wenn Sie möchten, dass die abgeleitete Klasse eine Implementierung einer bestimmten Methode bereitstellt, sollten Sie abstrakte Basisklassen verwenden. Schnittstellen sind genau das - Schnittstellen. Ein öffentlicher Auftrag, sonst nichts. Stellen Sie sich Schnittstellen als Spezifikation vor, die beschreibt, wie die Implementierung nach außen aussehen soll. Eine Spezifikation für einen zweipoligen Stecker gibt nicht an (zumindest gehe ich davon aus), wie seine interne Struktur aussehen sollte. Es muss lediglich schnittstellenkompatibel sein mit einer Steckdose .  Plug
(Quelle: made-in-china.com )

48
Anton Gogolev

Weil es keinen Sinn macht. Eine Schnittstelle ist ein öffentlich zugänglicher Vertrag. Ich bin ein IThing, daher werde ich auf Anfrage IThing-Methoden anwenden. Sie können von einem IThing keine Bestätigung verlangen, dass es Methoden ausführt, von denen es Ihnen nichts sagt.

15
annakata

Es gibt Schnittstellen, über die Personen auf Ihre Klasse zugreifen können, ohne die konkrete Implementierung zu kennen. Sie trennt die Implementierung vollständig vom Datenübertragungsvertrag. 

Daher muss alles in einer Schnittstelle öffentlich sein. Nichtöffentliche Mitglieder sind nur nützlich, wenn Sie Zugriff auf die Implementierung haben und daher keinen bedeutenden Beitrag zu einer Schnittstellendefinition leisten.

9
JaredPar

Schnittstellenmitglieder sind eine öffentliche API; Dinge wie protected etc sind Implementierungsdetails - und Schnittstellen haben keine Implementierung von haben. Ich vermute, Sie suchen eine explizite Schnittstellenimplementierung:

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

Eine Schnittstelle ist ein Vertrag, der den Kunden eine bestimmte Funktionalität verspricht. Mit anderen Worten, der Zweck einer Schnittstelle besteht darin, einen Typ in diese hineinzulegen und ihn so an Code weiterzuleiten, der die von dieser Schnittstelle garantierten Funktionen benötigt. Da der Clientcode eines Typs nicht auf geschützte Elemente dieses Typs zugreifen kann, ist es nicht sinnvoll, geschützte Elemente in einer Schnittstelle zu deklarieren.

1

Eine Schnittstelle ist wie die Form eines Schlüssels.

 enter image description here

Es ist nicht der Schlüssel.

Es ist nicht das Schloss.

Es ist nur der schlanke Kontaktpunkt.

Aus diesem Grund müssen alle Mitglieder der Benutzeroberfläche (die die Form des Schlüssels definiert) öffentlich sein.

Für einen Schlüssel zum Öffnen eines Schlosses ist es wichtig, dass beide die gleiche Form haben.

Indem Sie die Form (die Schnittstelle) public erstellen, können Sie andere kompatible Sperren oder kompatible Schlüssel erstellen.

Andernfalls, wenn Sie es (die Schnittstelle) internal machen, können andere keine kompatiblen Sperren oder kompatiblen Schlüssel erstellen.

1
Marco Staffoli

Bei einer Schnittstelle geht es nur darum, was ein bestimmtes Objekt tun kann. Wenn also eine Klasse verwendet wird, die diese Schnittstelle implementiert, erwartet der Entwickler, dass alle Elemente implementiert sind. Der geschützte Zugriffsmodifizierer bedeutet also nichts für Schnittstellen.

0
Gerrie Schenck

Eine Schnittstelle enthält nur öffentliche Mitglieder. Geschützt bedeutet, dass das, was Sie deklarieren, nur für die Klasse und die abgeleiteten Klasseninstanzen verfügbar ist.

0
Jason Punyon

Beim derzeitigen Design der Schnittstellen gibt es ein gutes Urteilsvermögen, das den Implementierern größere Flexibilität bietet. Denken Sie daran, dass Schnittstellen häufig von Framework-Programmierern geschrieben werden, und Implementierer unterscheiden sich. Die Umsetzung durchzusetzen wäre unnötig hart.

0

Durch die Implementierung einer Schnittstelle gibt der Typ an, dass er bestimmte Methoden unterstützt. Wenn eine dieser Methoden nicht öffentlich wäre, wäre sie für Anrufer nicht verfügbar, und der Typ würde die Schnittstelle nicht wie angegeben unterstützen. 

0
Brian Rasmussen

Jede Klasse, die eine .net-Schnittstelle implementiert, muss Implementierungen aller Schnittstellenmitglieder enthalten. Außerdem kann jede Klasse einer abgeleiteten Klasse die von ihnen gewünschten Mitglieder ausstellen. Das Erfordernis, dass eine Implementierung einer Schnittstelle ein Mitglied enthalten muss, das nur von abgeleiteten Klassen verwendet werden kann, würde keinen nützlichen Zweck erfüllen, es sei denn (1) ein solches Mitglied könnte für etwas außerhalb der Schnittstelle sichtbar sein oder (2) Schnittstellenimplementierungen könnten verwendet werden Mitglieder, die sie selbst nicht definiert haben. Wenn Schnittstellen geschachtelte Klassen einschließen dürfen (die auf die protected-Member der Schnittstellen zugreifen könnten), wären protected-Schnittstellenmitglieder sinnvoll. Sie können sehr nützlich sein, wenn eine in eine Schnittstelle geschachtelte Klasse Erweiterungsmethoden für diese Schnittstelle definieren kann. Leider existiert keine solche Einrichtung.

Übrigens, selbst wenn Klassen in Schnittstellen nicht verschachtelt werden können, wäre es dennoch nützlich, einen Zugriffsmodifizierer internal auf Schnittstellenmitglieder anzuwenden, so dass nur die Assembly, in der die Schnittstelle definiert ist, Implementierungen dafür definieren kann.

0
supercat