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 IOrange
würde die Schnittstelle garantieren, dass Implementierer ihren Erben mindestens eine OrangePips
Instanz bereitstellen . Wenn der Implementierer wollte, konnte er den Umfang vollständig erweitern 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); } }
}
Die Absicht der protected
Mitglieder auf Schnittstellen besteht darin, einen Supportvertrag für Erben (Unterklassen) bereitzustellen , zum Beispiel:
public class SpecialNavelOrange : NavelOrange
{
...
// Having a seed value is useful to me.
OrangePips seeds = this.Seeds;
...
}
(Zugegeben, das würde bei struct
s nicht funktionieren )
Ich kann nicht viel von einem Fall für private
oder internal
Modifikatoren in Schnittstellen sehen, aber die Unterstützung von beiden public
und protected
Modifikatoren scheint vollkommen vernünftig.
Ich werde versuchen, die Nützlichkeit von protected
Mitgliedern auf interface
s zu erklären, indem ich sie interface
vollständig von s trenne:
Stellen wir uns ein neues C # -Schlüsselwort vor, support
um Erbverträ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 ihren Erben geschützte Mitglieder 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 die protected
Mitglieder überhaupt erst zur Verfügung stellen.
Aber dann könnten wir auch folgendes tun:
public interface IOrange : IOrangeSupport
{
...
}
Dabei gilt dies IOrangeSupport
für alle Klassen IOrange
, die bestimmte protected
Mitglieder implementieren und von ihnen verlangen - was wir derzeit nicht tun können.
quelle
class Base<T> { }
interface IDerived
{
string Secret { get; set; }
}
class Derived<T> : Base<T>, IDerived
{
protected string Secret;
protected void LearnSecret(IDerived other)
{
var x = other.Secret;
}
}
Antworten:
Ich denke, jeder hat den Punkt einer Schnittstelle getroffen, 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); } } }
Bearbeiten: Es ist fair zu argumentieren, dass wenn wir eine PlasticOrange haben, die von einem Klassenornament abgeleitet ist, sie nur IOrange und nicht die Seeds-geschützte Methode implementieren kann. Das ist gut. Eine Schnittstelle ist per Definition ein Vertrag zwischen einem Aufrufer und einem Objekt, nicht zwischen einer Klasse und ihren Unterklassen. Die abstrakte Klasse ist so nah wie wir diesem Konzept kommen. Und das ist gut so. Was Sie im Wesentlichen vorschlagen, ist ein anderes Konstrukt in der Sprache, mit dem wir Unterklassen von einer Basisklasse zu einer anderen wechseln können, ohne den Build zu unterbrechen. Für mich macht das keinen Sinn.
Wenn Sie eine Unterklasse einer Klasse erstellen, ist die Unterklasse eine Spezialisierung der Basisklasse. Es sollte alle geschützten Mitglieder der Basisklasse vollständig kennen. Wenn Sie jedoch plötzlich die Basisklasse ausschalten möchten, macht es keinen Sinn, dass die Unterklasse mit jedem anderen IOrange funktioniert.
Ich nehme an, Sie haben eine faire Frage, aber es scheint ein Eckfall zu sein, und ich sehe ehrlich gesagt keinen Nutzen daraus.
quelle
NavelOrange
undValenciaOrange
auf dasselbe zu setzen. Angenommen, eine Klasse,PlasticOrange
die bereits von abgeleitet istOrnament
.Ich kann nicht sehen, warum man das will. Wenn Sie möchten, dass abgeleitete Klassen eine Implementierung einer bestimmten Methode bereitstellen, wählen Sie abstrakte Basisklassen. Schnittstellen sind genau das - Schnittstellen. Ein öffentlicher Auftrag, sonst nichts. Stellen Sie sich die Schnittstelle als eine Spezifikation vor, die beschreibt, wie die Implementierung nach außen aussehen soll. Eine Spezifikation für einen zweipoligen Stecker gibt nicht an (zumindest nehme ich das an), wie seine interne Struktur aussehen sollte. Es muss nur mit einer Steckdose kompatibel sein. (Quelle: made-in-china.com )
quelle
Weil es keinen Sinn macht. Eine Schnittstelle ist ein öffentlich zugänglicher Vertrag. Ich bin ein IThing, daher werde ich auf Anfrage IThing-Methoden durchführen. Sie können ein IThing nicht bitten, zu bestätigen, dass es Methoden ausführt, von denen es Ihnen nichts erzählen kann.
quelle
public
Methoden erzählen . Warum kann ich es nicht bitten, in diesem Zusammenhang zusätzliche IThing-Methoden durchzuführen?Es gibt Schnittstellen, über die Personen auf Ihre Klasse zugreifen können, ohne die konkrete Implementierung zu kennen. Die Implementierung wird vollständig vom Datenübertragungsvertrag getrennt.
Daher muss alles in einer Schnittstelle öffentlich sein. Nicht öffentliche Mitglieder sind nur dann nützlich, wenn Sie Zugriff auf die Implementierung haben und daher keinen sinnvollen Beitrag zu einer Schnittstellendefinition leisten.
quelle
Schnittstellenmitglieder sind eine öffentliche API. Dinge wie
protected
usw. sind Implementierungsdetails - und Schnittstellen haben keine Implementierung. Ich vermute, was Sie suchen, ist eine explizite Schnittstellenimplementierung:public class NavelOrange : IOrange { public OrangePeel Peel { get { return new OrangePeel(); } } OrangePips IOrange.Seeds { get { return null; } } }
quelle
public
, daher ist es nicht wirklich das, wonach ich suche. Insbesondere denke ich, dassprotected
Mitglieder eine API zwischen Gruppen von Basisklassen und ihren Erben bereitstellen würden.Eine Schnittstelle ist wie die Form eines Schlüssels.
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 Schnittstelle (die die Form des Schlüssels definiert) öffentlich sein.
Damit ein Schlüssel ein Schloss öffnen kann, ist es wichtig, dass beide dieselbe Form haben.
Indem Sie die Form (die Benutzeroberfläche) öffentlich machen , können Sie andere kompatible Schlösser oder kompatible Schlüssel erstellen lassen.
Wenn Sie es (die Schnittstelle) intern machen , können andere Benutzer keine kompatiblen Schlösser oder kompatiblen Schlüssel erstellen.
quelle
Eine Schnittstelle ist ein Vertrag, der Kunden bestimmte Funktionen verspricht. Mit anderen Worten, der Zweck einer Schnittstelle besteht darin, einen Typ in sie umwandeln und auf diese Weise an Code weitergeben zu können, der die von dieser Schnittstelle garantierten Funktionen benötigt. Da Client-Code eines Typs nicht auf geschützte Mitglieder dieses Typs zugreifen kann, ist es nicht sinnvoll, geschützte Elemente in einer Schnittstelle zu deklarieren.
quelle
Im Gegensatz zu abstrakten Basisklassen würden geschützte Schnittstellen eine "Mehrfachvererbung" (von abstrakten Klassen) ermöglichen, die ich ein- oder zweimal als nützlich empfunden hätte ...
quelle
Bei einer Schnittstelle geht es darum, was ein bestimmtes Objekt tun kann. Wenn Sie also eine Klasse verwenden, die diese Schnittstelle implementiert, erwartet der Entwickler, dass alle Mitglieder implementiert werden, sodass der Modifikator für den geschützten Zugriff für Schnittstellen keine Bedeutung hat.
quelle
Das derzeitige Design von Schnittstellen ist fundiert und bietet Implementierern mehr Flexibilität. Denken Sie daran, dass Schnittstellen sehr oft von Framework-Programmierern geschrieben werden und Implementierer unterschiedliche Leute sind. Die Durchsetzung durchzusetzen wäre unnötig hart.
quelle
Durch die Implementierung einer Schnittstelle gibt der Typ an, dass er einen bestimmten Satz von Methoden unterstützt. Wenn eine dieser Methoden nicht öffentlich wäre, wäre sie für Anrufer nicht verfügbar, und daher würde der Typ die angegebene Schnittstelle nicht unterstützen.
quelle
Eine Schnittstelle enthält nur öffentliche Mitglieder. Geschützt bedeutet, dass alles, was Sie deklarieren, nur für die Klasse und abgeleitete Klasseninstanzen verfügbar ist.
quelle
Jede Klasse, die eine .net-Schnittstelle implementiert, muss Implementierungen aller Schnittstellenmitglieder enthalten. Darüber hinaus kann jede Klasse einer abgeleiteten Klasse beliebige Mitglieder aussetzen. 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, entweder (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 verschachtelte Klassen enthalten dürfen (die auf die
protected
Mitglieder der Schnittstellen zugreifen können ), dannprotected
Schnittstellenmitglieder wären sinnvoll. In der Tat könnten sie sehr nützlich sein, wenn eine in einer Schnittstelle verschachtelte Klasse Erweiterungsmethoden für diese Schnittstelle definieren könnte. Leider gibt es keine solche Einrichtung.Übrigens wäre es auch ohne die Möglichkeit, Klassen in Schnittstellen zu verschachteln, nützlich, einen
internal
Zugriffsmodifikator auf Schnittstellenmitglieder anzuwenden , so dass nur die Assembly, in der die Schnittstelle definiert ist, Implementierungen dafür definieren kann.quelle