Angenommen, ich möchte eine ICar
Schnittstelle und alle Implementierungen enthalten das Feld Year
. Bedeutet dies, dass jede Implementierung separat deklariert werden muss Year
? Wäre es nicht schöner, dies einfach in der Benutzeroberfläche zu definieren?
223
Antworten:
Obwohl viele der anderen Antworten auf semantischer Ebene richtig sind, finde ich es interessant, diese Art von Fragen auch auf der Ebene der Implementierungsdetails zu beantworten.
Eine Schnittstelle kann als eine Sammlung von Slots betrachtet werden , die Methoden enthalten . Wenn eine Klasse eine Schnittstelle implementiert, muss die Klasse der Laufzeit mitteilen, wie alle erforderlichen Slots ausgefüllt werden sollen. Wenn du sagst
Die Klasse sagt: "Wenn Sie eine Instanz von mir erstellen, geben Sie einen Verweis auf Foo.M in den Steckplatz für IFoo.M ein.
Wenn Sie dann einen Anruf tätigen:
Der Compiler generiert Code mit der Aufschrift "Fragen Sie das Objekt, welche Methode sich im Steckplatz für IFoo.M befindet, und rufen Sie diese Methode auf.
Wenn eine Schnittstelle eine Sammlung von Slots ist, die Methoden enthalten, können einige dieser Slots auch die Methoden get und set einer Eigenschaft, die Methoden get und set eines Indexers sowie die Methoden add und remove eines Ereignisses enthalten. Aber ein Feld ist keine Methode . Einem Feld ist kein "Slot" zugeordnet, den Sie dann mit einem Verweis auf die Feldposition "ausfüllen" können. Daher können Schnittstellen Methoden, Eigenschaften, Indexer und Ereignisse definieren, jedoch keine Felder.
quelle
An interface cannot contain constants, fields, operators
. Von msdn.microsoft.com/en-us/library/ms173156.aspx )int One()
, ist die Implementierungpublic int One(){return 1;}
kein Feld.Schnittstellen in C # sollen den Vertrag definieren, an den sich eine Klasse halten wird - keine bestimmte Implementierung.
In diesem Sinne ermöglichen C # -Schnittstellen die Definition von Eigenschaften, für die der Aufrufer eine Implementierung bereitstellen muss:
Implementierende Klassen können Auto-Eigenschaften verwenden, um die Implementierung zu vereinfachen, wenn der Eigenschaft keine spezielle Logik zugeordnet ist:
quelle
Year
?public int Year => 123;
. In diesem Fall macht es jedoch keinen Sinn, einen Setter zu haben, sodass die Schnittstelle mitint Year { get; }
Deklarieren Sie es als eine Eigenschaft:
quelle
Eric Lippert hat es geschafft, ich werde anders sagen, was er gesagt hat. Alle Mitglieder einer Schnittstelle sind virtuell und müssen von einer Klasse überschrieben werden, die die Schnittstelle erbt. Sie schreiben weder das virtuelle Schlüsselwort explizit in die Schnittstellendeklaration, noch verwenden Sie das Schlüsselwort override in der Klasse, sie sind impliziert.
Das virtuelle Schlüsselwort wird in .NET mit Methoden und einer sogenannten V-Tabelle, einem Array von Methodenzeigern, implementiert. Das Schlüsselwort override füllt den v-Tabellen-Slot mit einem anderen Methodenzeiger und überschreibt den von der Basisklasse erzeugten. Eigenschaften, Ereignisse und Indexer werden als Methoden unter der Haube implementiert. Felder sind es aber nicht. Schnittstellen dürfen daher keine Felder enthalten.
quelle
Warum nicht einfach eine
Year
Immobilie haben, die vollkommen in Ordnung ist?Schnittstellen enthalten keine Felder, da Felder eine bestimmte Implementierung der Datendarstellung darstellen und deren Offenlegung die Kapselung unterbrechen würde. Eine Schnittstelle mit einem Feld zu haben, würde also effektiv eine Implementierung anstelle einer Schnittstelle codieren, was ein merkwürdiges Paradoxon für eine Schnittstelle ist!
Zum Beispiel
Year
könnte ein Teil Ihrer Spezifikation erfordern, dass es fürICar
Implementierer ungültig ist , die Zuordnung zu einem zuzulassen,Year
das später als das aktuelle Jahr + 1 oder vor 1900 ist. Es gibt keine Möglichkeit zu sagen, dass, wenn SieYear
Felder verfügbar gemacht hätten - weitaus besser zu verwenden Eigenschaften stattdessen die Arbeit hier zu erledigen.quelle
Die kurze Antwort lautet: Ja, jeder Implementierungstyp muss eine eigene Hintergrundvariable erstellen. Dies liegt daran, dass eine Schnittstelle einem Vertrag entspricht. Es kann lediglich bestimmte öffentlich zugängliche Codeteile angeben, die ein Implementierungstyp zur Verfügung stellen muss. Es kann keinen Code selbst enthalten.
Betrachten Sie dieses Szenario anhand Ihrer Vorschläge:
Wir haben hier ein paar Probleme:
myBackingVariable
wirdMyClass
verwendet?Der gebräuchlichste Ansatz besteht darin, die Schnittstelle und eine abstrakte Barebone-Klasse zu deklarieren, die sie implementiert. Dies gibt Ihnen die Flexibilität, entweder von der abstrakten Klasse zu erben und die Implementierung kostenlos zu erhalten oder die Schnittstelle explizit zu implementieren und von einer anderen Klasse erben zu dürfen. Es funktioniert ungefähr so:
quelle
Andere haben das "Warum" angegeben, daher füge ich nur hinzu, dass Ihre Schnittstelle ein Steuerelement definieren kann. Wenn Sie es in eine Eigenschaft einwickeln:
quelle
Schnittstellen enthalten keine Implementierung.
quelle
Es wurde bereits viel gesagt, aber um es einfach zu machen, hier ist meine Meinung. Schnittstellen sollen Methodenverträge haben, die von den Verbrauchern oder Klassen implementiert werden sollen, und keine Felder zum Speichern von Werten.
Sie können argumentieren, warum dann Eigenschaften erlaubt sind? Die einfache Antwort lautet also: Eigenschaften werden intern nur als Methoden definiert.
quelle
Zu diesem Zweck können Sie eine Car-Basisklasse haben, die das Jahr-Feld implementiert, und alle anderen Implementierungen können von diesem erben.
quelle
Eine Schnittstelle definiert Eigenschaften und Methoden öffentlicher Instanzen. Felder sind normalerweise privat oder höchstens geschützt, intern oder geschützt intern (der Begriff "Feld" wird normalerweise für nichts Öffentliches verwendet).
Wie in anderen Antworten angegeben, können Sie eine Basisklasse definieren und eine geschützte Eigenschaft definieren, auf die alle Erben zugreifen können.
Eine Kuriosität ist, dass eine Schnittstelle zwar als intern definiert werden kann, aber die Nützlichkeit der Schnittstelle einschränkt. Sie wird normalerweise verwendet, um interne Funktionen zu definieren, die von keinem anderen externen Code verwendet werden.
quelle