W przypadku interfejsu dodanie słów kluczowych abstract
lub nawet public
słów kluczowych byłoby zbędne, więc je pomijasz:
interface MyInterface {
void Method();
}
W CIL metoda jest oznaczona virtual
i abstract
.
(Należy zauważyć, że Java umożliwia deklarowanie elementów interfejsu public abstract
).
W przypadku klasy implementującej istnieje kilka opcji:
Niezastąpiona : w C # klasie nie deklaruje metody jako virtual
. Oznacza to, że nie można go przesłonić w klasie pochodnej (tylko ukryty). W CIL metoda jest nadal wirtualna (ale zapieczętowana), ponieważ musi obsługiwać polimorfizm dotyczący typu interfejsu.
class MyClass : MyInterface {
public void Method() {}
}
Zastępowalne : zarówno w C #, jak iw CIL metoda jest virtual
. Uczestniczy w wysyłce polimorficznej i może zostać nadpisany.
class MyClass : MyInterface {
public virtual void Method() {}
}
Jawny : w ten sposób klasa może zaimplementować interfejs, ale nie udostępnia metod interfejsu w interfejsie publicznym samej klasy. W CIL metoda będzie private
(!), Ale nadal będzie można ją wywołać spoza klasy z odniesienia do odpowiedniego typu interfejsu. Jawne implementacje również nie podlegają zastąpieniu. Jest to możliwe, ponieważ istnieje dyrektywa CIL ( .override
), która połączy metodę prywatną z odpowiednią metodą interfejsu, którą implementuje.
[DO#]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
W VB.NET można nawet utworzyć alias nazwy metody interfejsu w klasie implementującej.
[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
}
Rozważmy teraz ten dziwny przypadek:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
Jeśli Base
i Derived
są zadeklarowane w tym samym zestawie, kompilator utworzy Base::Method
wirtualny i zapieczętowany (w CIL), mimo żeBase
nie implementuje interfejsu.
Jeśli Base
i Derived
znajdują się w różnych Derived
zestawach , podczas kompilowania zestawu kompilator nie zmieni innego zestawu, więc wprowadzi element członkowski, Derived
który będzie jawną implementacją MyInterface::Method
, która po prostu deleguje wywołanie do Base::Method
.
Jak widać, każda implementacja metody interfejsu musi obsługiwać zachowanie polimorficzne, a zatem musi być oznaczona jako wirtualna w CIL, nawet jeśli kompilator musi przejść przez obręcze, aby to zrobić.
Tak, metody implementacji interfejsu są wirtualne, jeśli chodzi o środowisko wykonawcze. Jest to szczegół implementacyjny, który sprawia, że interfejsy działają. Metody wirtualne pobierają sloty w tabeli v-table klasy, każdy slot ma wskaźnik do jednej z metod wirtualnych. Rzutowanie obiektu na typ interfejsu generuje wskaźnik do sekcji tabeli, która implementuje metody interfejsu. Kod klienta, który używa odwołania do interfejsu, widzi teraz pierwszy wskaźnik metody interfejsu na przesunięciu 0 od wskaźnika interfejsu itp.
W mojej pierwotnej odpowiedzi nie doceniłem znaczenia ostatniego atrybutu. Zapobiega zastąpieniu metody wirtualnej przez klasę pochodną. Klasa pochodzi musi CMC interfejs sposoby realizacji cień metod klasy bazowej. To wystarczy, aby zaimplementować kontrakt języka C #, który mówi, że metoda implementacji nie jest wirtualna.
Jeśli zadeklarujesz metodę Dispose () w klasie Example jako wirtualną, zobaczysz, że ostatni atrybut zostanie usunięty. Teraz pozwalam klasie pochodnej na przesłonięcie go.
źródło
W większości innych środowisk kodu skompilowanego interfejsy są implementowane jako vtables - lista wskaźników do treści metod. Zazwyczaj klasa, która implementuje wiele interfejsów, będzie miała gdzieś w swoich wewnętrznych metadanych wygenerowanych przez kompilator listę vtables interfejsów, po jednej tabeli vtable na interfejs (aby zachować kolejność metod). W ten sposób zazwyczaj implementuje się również interfejsy COM.
Jednak w .NET interfejsy nie są implementowane jako oddzielne vtables dla każdej klasy. Metody interfejsu są indeksowane za pośrednictwem globalnej tabeli metod interfejsu, której częścią są wszystkie interfejsy. Dlatego też nie jest konieczne deklarowanie metody wirtualnej, aby ta metoda implementowała metodę interfejsu - tabela metod interfejsu globalnego może po prostu wskazywać bezpośrednio na adres kodowy metody klasy.
Deklarowanie metody wirtualnej w celu zaimplementowania interfejsu nie jest również wymagane w innych językach, nawet na platformach innych niż CLR. Jednym z przykładów jest język Delphi w systemie Win32.
źródło
Nie są wirtualne (jeśli chodzi o to, jak o nich myślimy, jeśli nie w kategoriach podstawowej implementacji jako (zapieczętowanej wirtualnej) - dobrze przeczytać inne odpowiedzi tutaj i nauczyć się czegoś sam :-)
Niczego nie zastępują - w interfejsie nie ma implementacji.
Interfejs dostarcza jedynie „kontrakt”, do którego klasa musi się stosować - wzorzec, jeśli chcesz, aby wywołujący wiedzieli, jak wywołać obiekt, nawet jeśli nigdy wcześniej nie widzieli tej konkretnej klasy.
Do klasy należy następnie implementacja metody interfejsu tak, jak to zrobi, w ramach kontraktu - wirtualna lub „niewirtualna” (jak się okazuje zapieczętowana wirtualna).
źródło
Interfejsy są bardziej abstrakcyjnym pojęciem niż klasy, kiedy deklarujesz klasę, która implementuje interfejs, po prostu mówisz „klasa musi mieć te konkretne metody z interfejsu i nie ma znaczenia, czy statyczne , wirtualne , niewirtualne , nadpisane , jak o ile ma ten sam identyfikator i te same parametry typu ”.
Inne języki obsługujące interfejsy, takie jak Object Pascal („Delphi”) i Objective-C (Mac), nie wymagają oznaczania metod interfejsu jako wirtualnych, a nie wirtualnych.
Ale możesz mieć rację, myślę, że dobrym pomysłem może być posiadanie określonego atrybutu „virtual” / „override” w interfejsach, na wypadek gdybyś chciał ograniczyć metody klas, które implementują określony interfejs. Ale oznacza to również, że dla obu interfejsów mają być słowa kluczowe „nie wirtualne”, „dontcareifvirtual ornot”.
Rozumiem twoje pytanie, ponieważ widzę coś podobnego w Javie, gdy metoda klasowa musi używać „@virtual” lub „@override”, aby upewnić się, że metoda ma być wirtualna.
źródło
override
jest pierwszorzędnym słowem kluczowym w samym języku.