119 votes

Pourquoi les méthodes d’interface c# non déclarés abstraite ou virtuelle ?

C# méthodes dans les interfaces sont déclarées sans l'aide de l' virtual mot-clé, et remplacé dans la classe dérivée sans l'aide de l' override mot-clé.

Est-il une raison pour cela? Je suppose que c'est juste une commodité de langage, et, évidemment, le CLR sait comment gérer ce sous les couvertures (méthodes ne sont pas virtuels par défaut), mais il existe d'autres raisons techniques?

Voici le IL que une classe dérivée génère:

class Example : IDisposable {
    public void Dispose() { }
}

.method public hidebysig newslot virtual final 
        instance void  Dispose() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Example::Dispose

Notez que la méthode est déclarée virtual final dans l'IL.

156voto

Jordão Points 29221

Pour l'interface, l'ajout de l' abstract, ou même l' public mots clés serait redondante, vous omettez:

interface MyInterface {
  void Method();
}

Dans le CIL, la méthode est marquée virtual et abstract.

(Notez que Java permet aux membres d'interface afin d'être déclarée public abstract).

Pour la mise en œuvre de la classe, il y a quelques options:

Non substituables: En C# la classe de ne pas déclarer la méthode virtual. Ce qui signifie qu'il ne peut pas être redéfinie dans une classe dérivée (seulement caché). Dans le CIL de la méthode est encore virtuel (mais scellée), car il doit prendre en charge le polymorphisme concernant le type d'interface.

class MyClass : MyInterface {
  public void Method() {}
}

Substituables: à la Fois en C# et dans le CIL de la méthode est - virtual. Il participe à des polymorphes de répartition et elle peut être remplacée.

class MyClass : MyInterface {
  public virtual void Method() {}
}

Explicite: C'est une façon pour qu'une classe implémente une interface, mais ne pas fournir les méthodes d'interface dans l'interface publique de la classe elle-même. Dans le CIL de la méthode sera private (!) mais il faudra encore être appelée à partir de l'extérieur de la classe à partir d'une référence à l'interface correspondante type. Explicite implémentations sont également non-substituables. Cela est possible parce qu'il y a un CIL de la directive (.override) qui fera le lien entre la méthode privée à l'interface correspondante méthode de mise en œuvre.

[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 alias l'interface nom de la méthode dans la mise en œuvre de la classe.

[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, pensez à cette étrange affaire:

interface MyInterface {
  void Method();
}
class Base {
  public void Method();
}
class Derived : Base, MyInterface { }

Si Base et Derived sont déclarées dans la même assemblée, le compilateur fera Base::Method virtuel et scellé (CIL), même si l' Base n'implémente pas l'interface.

Si Base et Derived sont dans les différentes assemblées, lors de la compilation de l' Derived de l'assemblée, le compilateur ne va pas changer l'autre assemblée, de sorte qu'il présentera un membre en Derived qui sera une mise en œuvre explicite pour MyInterface::Method qui va juste déléguer l'appel d' Base::Method.

Donc, vous voyez, chaque méthode de l'interface de mise en œuvre doit prendre en charge le comportement polymorphique, et doit donc être marqué virtuel sur le CIL, même si le compilateur doit passer à travers des cerceaux pour le faire.

78voto

Usman Khan Points 597

Citant Jeffrey Ritcher de CLR via CSharp 3e Édition ici

Le common language runtime exige que l'interface méthodes être marqué comme virtuel. Si vous ne pas marquer explicitement la méthode virtuel dans votre code source, le compilateur marques de la méthode virtuelle et scellé; cela empêche un dérivé classe de remplacer l'interface la méthode. Si vous marquer explicitement la méthode virtuelle, le compilateur marques la méthode virtuelle (et laisse non scellés); ce qui permet d'une classe dérivée pour remplacer la méthode de l'interface. Si une méthode d'interface est scellé, un la classe dérivée ne peut pas remplacer la la méthode. Cependant, une classe dérivée peut re-héritent de la même interface et fournir sa propre mise en œuvre de la l'interface des méthodes.

14voto

Hans Passant Points 475940

Oui, l'interface de mise en œuvre de méthodes sont virtuelles autant que le moteur d'exécution. C'est un détail d'implémentation, il rend les interfaces de travail. Les méthodes virtuelles d'obtenir des fentes dans la classe des' v-table, chaque logement dispose d'un pointeur vers l'une des méthodes virtuelles. Le coulage d'un objet à un type d'interface génère un pointeur vers la partie du tableau qui implémente les méthodes d'interface. Le code client qui utilise la référence de l'interface de voit maintenant la première méthode de l'interface pointeur à la position 0 du pointeur d'interface, et cætera.

Ce que j'ai sous-estimé dans ma réponse originale à cette question est la signification de la finale de l'attribut. Il empêche une classe dérivée de substitution de la méthode virtuelle. Une classe dérivée doit ré-implémenter l'interface, les méthodes de mise en œuvre de l'ombre à la base des méthodes de la classe. Ce qui est suffisant pour mettre en œuvre le langage C# contrat qui dit que la mise en œuvre de la méthode n'est pas virtuel.

Si vous déclarez la méthode dispose() dans l'Exemple de la classe virtuelle, vous verrez la finale de l'attribut obtenir supprimé. Maintenant, permettant une classe dérivée pour le remplacer.

4voto

dthorpe Points 23314

Dans la plupart des autres code compilé les environnements, les interfaces sont implémentées comme vtables - une liste de pointeurs vers les corps de méthode. Généralement une classe qui implémente plusieurs interfaces aurez quelque part dans son interne généré par le compilateur, les métadonnées d'une liste d'interface pour les vtables, une vtable par interface (de sorte que la méthode de commande est conservé). C'est la façon dont les interfaces COM sont généralement mis en œuvre.

Dans .NET, même si, les interfaces ne sont pas mis en œuvre comme distinctes vtables pour chaque classe. Les méthodes d'Interface sont indexés par le biais d'une interface globale de la méthode de la table que toutes les interfaces sont une partie de. Par conséquent, il n'est pas nécessaire de déclarer une méthode virtuelle dans l'ordre pour que la méthode à mettre en œuvre une méthode d'interface - l'interface globale de la méthode de table suffit de pointer vers l'adresse de code de la classe de la méthode directement.

Déclarer une méthode virtuelle afin de mettre en œuvre une interface n'est pas nécessaire dans d'autres langues, même en non-CLR plates-formes. Le langage Delphi sur Win32, en est un exemple.

1voto

umlcat Points 2025

<joke>C'est quelque chose que vous voulez poser à Anders Hejlsberg et le reste du C# de l'équipe de conception.</blague>

Les Interfaces sont un concept plus abstrait que de classes, lorsque vous déclarez une classe qui implémente une interface, vous venez de dire "la classe doit avoir de ces méthodes particulières de l'interface, et n'a pas d'importance si statique, virtuel, non virtuel, bien sûr, aussi longtemps que il ont le même I. D. et le même type de paramètres" .

D'autres langages qui prennent en charge les interfaces de l'Objet en Pascal (Delphi) et de l'Objective-C (Mac) ne nécessite pas d'interface des méthodes pour être marqué virtuel et non virtuel.

Mais, vous avez peut-être raison, je pense que peut être une bonne idée d'avoir un "virtuel" / "remplacer" de l'attribut dans les interfaces, dans le cas où vous souhaitez restreindre les classes de méthodes qui implémentent une interface particulière. Mais, cela signifie aussi avoir un "nonvirtual", "dontcareifvirtualornot" mots-clés, pour les deux interfaces.

Je comprends votre question, parce que je vois quelque chose de similaire en Java, quand une méthode de classe est d'utiliser le "@virtuel" ou "@override" pour être sûr qu'une méthode est destinée à être virtuel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X