Pour l'interface, l'ajout du abstract
, voire des public
mots - clés serait redondant, vous les omettez donc:
interface MyInterface {
void Method();
}
Dans le CIL, la méthode est marquée virtual
et abstract
.
(Notez que Java autorise la déclaration des membres de l'interface public abstract
).
Pour la classe d'implémentation, il existe quelques options:
Non substituable : en C #, la classe ne déclare pas la méthode comme virtual
. Cela signifie qu'il ne peut pas être remplacé dans une classe dérivée (uniquement masquée). Dans le CIL, la méthode est toujours virtuelle (mais scellée) car elle doit supporter le polymorphisme concernant le type d'interface.
class MyClass : MyInterface {
public void Method() {}
}
Remplaçable : à la fois en C # et en CIL, la méthode est virtual
. Il participe à l'envoi polymorphe et peut être remplacé.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explicite : C'est un moyen pour une classe d'implémenter une interface mais de ne pas fournir les méthodes d'interface dans l'interface publique de la classe elle-même. Dans le CIL, la méthode sera private
(!) Mais elle sera toujours appelable de l'extérieur de la classe à partir d'une référence au type d'interface correspondant. Les implémentations explicites ne peuvent pas non plus être remplacées. Cela est possible car il existe une directive CIL ( .override
) qui liera la méthode privée à la méthode d'interface correspondante qu'elle implémente.
[C #]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
Dans VB.NET, vous pouvez même aliaser le nom de la méthode d'interface dans la classe d'implémentation.
[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
}
Maintenant, considérez ce cas étrange:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
Si Base
et Derived
sont déclarés dans le même assembly, le compilateur rendra Base::Method
virtuel et scellé (dans le CIL), même s'il Base
n'implémente pas l'interface.
Si Base
et Derived
sont dans des assemblys différents, lors de la compilation de l' Derived
assembly, le compilateur ne changera pas l'autre assembly, il introduira donc un membre dans Derived
qui sera une implémentation explicite car MyInterface::Method
cela déléguera simplement l'appel à Base::Method
.
Ainsi, vous voyez, chaque implémentation de méthode d'interface doit prendre en charge le comportement polymorphe, et doit donc être marquée virtuelle sur le CIL, même si le compilateur doit passer par des cercles pour le faire.
Oui, les méthodes d'implémentation d'interface sont virtuelles en ce qui concerne le runtime. C'est un détail d'implémentation, cela fait fonctionner les interfaces. Les méthodes virtuelles obtiennent des emplacements dans la v-table de la classe, chaque emplacement a un pointeur vers l'une des méthodes virtuelles. Le cast d'un objet en type d'interface génère un pointeur vers la section de la table qui implémente les méthodes d'interface. Le code client qui utilise la référence d'interface voit maintenant le premier pointeur de méthode d'interface à l'offset 0 du pointeur d'interface, etc.
Ce que j'ai sous-estimé dans ma réponse initiale, c'est la signification de l' attribut final . Il empêche une classe dérivée de remplacer la méthode virtuelle. Une classe dérivée doit réimplémenter l'interface, les méthodes d'implémentation reflètent les méthodes de classe de base. Ce qui est suffisant pour implémenter le contrat de langage C # qui dit que la méthode d'implémentation n'est pas virtuelle.
Si vous déclarez la méthode Dispose () dans la classe Example comme virtuelle, vous verrez l' attribut final être supprimé. Permettre maintenant à une classe dérivée de la remplacer.
la source
Dans la plupart des autres environnements de code compilé, les interfaces sont implémentées sous forme de vtables - une liste de pointeurs vers les corps de méthode. En général, une classe qui implémente plusieurs interfaces aura quelque part dans ses métadonnées générées par le compilateur interne une liste de vtables d'interface, une vtable par interface (afin que l'ordre des méthodes soit préservé). C'est ainsi que les interfaces COM sont généralement implémentées.
Dans .NET, cependant, les interfaces ne sont pas implémentées en tant que vtables distinctes pour chaque classe. Les méthodes d'interface sont indexées via une table de méthodes d'interface globale dont toutes les interfaces font partie. Par conséquent, il n'est pas nécessaire de déclarer une méthode virtual pour que cette méthode implémente une méthode d'interface - la table de méthode d'interface globale peut simplement pointer directement vers l'adresse de code de la méthode de la classe.
Déclarer une méthode virtuelle pour implémenter une interface n'est pas non plus nécessaire dans d'autres langages, même dans les plates-formes non CLR. Le langage Delphi sur Win32 en est un exemple.
la source
Ils ne sont pas virtuels (en termes de façon dont nous pensons à eux, sinon en termes de mise en œuvre sous-jacente en tant que (virtuel scellé) - il est bon de lire les autres réponses ici et d'apprendre quelque chose moi-même :-)
Ils ne remplacent rien - il n'y a aucune implémentation dans l'interface.
L'interface ne fait que fournir un "contrat" auquel la classe doit adhérer - un modèle, si vous le souhaitez, afin que les appelants sachent comment appeler l'objet même s'ils n'ont jamais vu cette classe particulière auparavant.
Il appartient à la classe d'implémenter ensuite la méthode d'interface comme elle le fera, dans les limites du contrat - virtuel ou «non virtuel» (virtuel scellé en fait).
la source
Les interfaces sont un concept plus abstrait que les classes, lorsque vous déclarez une classe qui implémente une interface, vous dites simplement "la classe doit avoir ces méthodes particulières de l'interface, et peu importe qu'elle soit statique , virtuelle , non virtuelle , surchargée , comme tant qu'il a le même ID et les mêmes paramètres de type ".
D'autres langages qui prennent en charge des interfaces comme Object Pascal ("Delphi") et Objective-C (Mac) ne nécessitent pas non plus que les méthodes d'interface soient marquées comme virtuelles et non virtuelles.
Mais, vous avez peut-être raison, je pense que c'est peut-être une bonne idée d'avoir un attribut spécifique "virtuel" / "override" dans les interfaces, au cas où vous voudriez restreindre les méthodes de classes qui implémentent une interface particulière. Mais, cela signifie aussi avoir un mot-clé «non virtuel», «dontcareifvirtualornot», pour les deux interfaces.
Je comprends votre question, car je vois quelque chose de similaire en Java, lorsqu'une méthode de classe doit utiliser le "@virtual" ou "@override" pour être sûr qu'une méthode est censée être virtuelle.
la source
override
est un mot-clé de première classe dans la langue elle-même.