Für die Benutzeroberfläche wäre das Hinzufügen der abstract
oder sogar der public
Schlüsselwörter redundant, sodass Sie sie weglassen:
interface MyInterface {
void Method();
}
In der CIL ist die Methode markiert virtual
und abstract
.
(Beachten Sie, dass mit Java Schnittstellenmitglieder deklariert werden können. public abstract
)
Für die implementierende Klasse gibt es einige Optionen:
Nicht überschreibbar : In C # deklariert die Klasse die Methode nicht als virtual
. Das bedeutet, dass es in einer abgeleiteten Klasse nicht überschrieben werden kann (nur versteckt). In der CIL ist die Methode immer noch virtuell (aber versiegelt), da sie den Polymorphismus hinsichtlich des Schnittstellentyps unterstützen muss.
class MyClass : MyInterface {
public void Method() {}
}
Overridable : Sowohl in C # als auch in CIL ist die Methode virtual
. Es nimmt am polymorphen Versand teil und kann überschrieben werden.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explizit : Dies ist eine Möglichkeit für eine Klasse, eine Schnittstelle zu implementieren, jedoch nicht die Schnittstellenmethoden in der öffentlichen Schnittstelle der Klasse selbst bereitzustellen. In der CIL ist die Methode private
(!), Kann jedoch weiterhin von außerhalb der Klasse über einen Verweis auf den entsprechenden Schnittstellentyp aufgerufen werden. Explizite Implementierungen können ebenfalls nicht überschrieben werden. Dies ist möglich, weil es eine CIL-Direktive ( .override
) gibt, die die private Methode mit der entsprechenden Schnittstellenmethode verknüpft, die sie implementiert.
[C #]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
In VB.NET können Sie sogar den Namen der Schnittstellenmethode in der implementierenden Klasse als Alias verwenden.
[VB.NET]
Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class
[CIL]
.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}
Betrachten Sie nun diesen seltsamen Fall:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
Wenn Base
und Derived
in derselben Assembly deklariert sind, wird der Compiler Base::Method
virtuell und versiegelt (in der CIL), obwohl Base
die Schnittstelle nicht implementiert wird.
Wenn Base
und Derived
sich in verschiedenen Assemblys befinden, Derived
ändert der Compiler beim Kompilieren der Assembly nicht die andere Assembly, sodass ein Mitglied eingeführt Derived
wird, das eine explizite Implementierung darstellt MyInterface::Method
, an die der Aufruf lediglich delegiert wird Base::Method
.
Sie sehen also, jede Implementierung der Schnittstellenmethode muss polymorphes Verhalten unterstützen und daher in der CIL als virtuell markiert sein, selbst wenn der Compiler dafür Hoops durchlaufen muss.
Ja, Schnittstellenimplementierungsmethoden sind hinsichtlich der Laufzeit virtuell. Es ist ein Implementierungsdetail, mit dem Schnittstellen funktionieren. Virtuelle Methoden erhalten Slots in der V-Tabelle der Klasse. Jeder Slot hat einen Zeiger auf eine der virtuellen Methoden. Durch das Umwandeln eines Objekts in einen Schnittstellentyp wird ein Zeiger auf den Abschnitt der Tabelle generiert, der die Schnittstellenmethoden implementiert. Der Client-Code, der die Schnittstellenreferenz verwendet, sieht jetzt den ersten Schnittstellenmethodenzeiger mit dem Offset 0 vom Schnittstellenzeiger usw.
Was ich in meiner ursprünglichen Antwort unterschätzt habe, ist die Bedeutung des endgültigen Attributs. Es verhindert, dass eine abgeleitete Klasse die virtuelle Methode überschreibt. Eine abgeleitete Klasse muss die Schnittstelle erneut implementieren. Die Implementierungsmethoden überschatten die Basisklassenmethoden. Dies reicht aus, um den C # -Sprachenvertrag zu implementieren, der besagt, dass die Implementierungsmethode nicht virtuell ist.
Wenn Sie die Dispose () -Methode in der Example-Klasse als virtuell deklarieren, wird das endgültige Attribut entfernt. Jetzt kann eine abgeleitete Klasse sie überschreiben.
quelle
In den meisten anderen kompilierten Codeumgebungen werden Schnittstellen als vtables implementiert - eine Liste von Zeigern auf die Methodenkörper. Normalerweise hat eine Klasse, die mehrere Schnittstellen implementiert, irgendwo in ihrem internen Compiler generierte Metadaten eine Liste von Schnittstellen-Vtables, eine Vtable pro Schnittstelle (damit die Methodenreihenfolge erhalten bleibt). Auf diese Weise werden in der Regel auch COM-Schnittstellen implementiert.
In .NET werden Schnittstellen jedoch nicht als separate vtables für jede Klasse implementiert. Schnittstellenmethoden werden über eine globale Schnittstellenmethodentabelle indiziert, zu der alle Schnittstellen gehören. Daher ist es nicht erforderlich, eine Methode als virtuell zu deklarieren, damit diese Methode eine Schnittstellenmethode implementiert. Die globale Schnittstellenmethoden-Tabelle kann nur direkt auf die Codeadresse der Klassenmethode verweisen.
Das Deklarieren einer virtuellen Methode zum Implementieren einer Schnittstelle ist auch in anderen Sprachen nicht erforderlich, selbst auf Nicht-CLR-Plattformen. Die Delphi-Sprache unter Win32 ist ein Beispiel.
quelle
Sie sind nicht virtuell (in Bezug darauf, wie wir sie sehen, wenn nicht in Bezug auf die zugrunde liegende Implementierung als (versiegelt virtuell) - gut, die anderen Antworten hier zu lesen und selbst etwas zu lernen :-)
Sie überschreiben nichts - es gibt keine Implementierung in der Schnittstelle.
Die Schnittstelle liefert lediglich einen "Vertrag", an den sich die Klasse halten muss - ein Muster, wenn Sie möchten, damit Aufrufer wissen, wie sie das Objekt aufrufen, selbst wenn sie diese bestimmte Klasse noch nie gesehen haben.
Es liegt an der Klasse, die Schnittstellenmethode innerhalb der Vertragsgrenzen wie gewünscht zu implementieren - virtuell oder "nicht virtuell" (wie sich herausstellt, versiegelt virtuell).
quelle
Schnittstellen sind ein abstrakteres Konzept als Klassen. Wenn Sie eine Klasse deklarieren, die eine Schnittstelle implementiert, sagen Sie nur: "Die Klasse muss diese bestimmten Methoden von der Schnittstelle haben und spielt keine Rolle, ob statisch , virtuell , nicht virtuell , überschrieben , als solange es die gleiche ID und die gleichen Typparameter hat ".
Andere Sprachen, die Schnittstellen wie Object Pascal ("Delphi") und Objective-C (Mac) unterstützen, erfordern nicht, dass Schnittstellenmethoden als virtuell und nicht als virtuell markiert werden.
Aber Sie haben vielleicht Recht, ich denke, es ist eine gute Idee, ein bestimmtes Attribut "virtuell" / "überschreiben" in Schnittstellen zu haben, falls Sie die Klassenmethoden einschränken möchten , die eine bestimmte Schnittstelle implementieren. Dies bedeutet jedoch auch, dass für beide Schnittstellen die Schlüsselwörter "nicht virtuell" und "nicht pflegebedürftig" nicht vorhanden sind.
Ich verstehe Ihre Frage, weil ich in Java etwas Ähnliches sehe, wenn eine Klassenmethode "@virtual" oder "@override" verwenden muss, um sicherzugehen, dass eine Methode virtuell sein soll.
quelle
override
ist ein erstklassiges Schlüsselwort in der Sprache selbst.