En C #, une classe peut-elle hériter d'une autre classe et d'une interface?

130

Je veux savoir si une classe peut hériter d'une classe et d'une interface. L'exemple de code ci-dessous ne fonctionne pas mais je pense qu'il exprime ce que je veux faire. La raison pour laquelle je veux faire cela est que dans mon entreprise, nous fabriquons des périphériques USB, série, Ethernet, etc. J'essaie de développer un composant / une interface générique que je peux utiliser pour écrire des programmes pour tous nos appareils qui aideront à garder les choses courantes (comme la connexion, la déconnexion, l'obtention du micrologiciel) les mêmes pour toutes nos applications.

Pour ajouter à cette question: Si GenericDevice est dans un projet différent, puis-je mettre l'interface IOurDevices dans ce projet, puis faire en sorte que la classe USBDevice implémente l'interface si j'ajoute une référence au premier projet? Parce que je voudrais simplement référencer un projet, puis implémenter différentes interfaces en fonction de l'appareil.

class GenericDevice
{
   private string _connectionState;
   public connectionState
   {
      get{return _connectionState; }
      set{ _connectionState = value;}
   }
}

interface IOurDevices
{
   void connectToDevice();
   void DisconnectDevice();
   void GetFirmwareVersion();
}

class USBDevice : IOurDevices : GenericDevice
{
   //here I would define the methods in the interface
   //like this...
   void connectToDevice()
   {
       connectionState = "connected";
   }
}

//so that in my main program I can do this...

class myProgram
{
   main()
   {
      USBDevice myUSB = new USBDevice();
      myUSB.ConnectToDevice;
   }
}
PICyourBrain
la source
5
Pour votre référence future, la section 10.1.4 de la spécification C # décrit précisément comment déclarer une classe qui a plusieurs types de base.
Eric Lippert
@Eric Lippert: Pourriez-vous s'il vous plaît m'aider à comprendre à propos de cette affaire si elle est correcte et sera disponible à l'avenir?
Gul Md Ershad

Réponses:

246

Oui. Essayer:

class USBDevice : GenericDevice, IOurDevice

Remarque: la classe de base doit précéder la liste des noms d'interface.

Bien sûr, vous devrez toujours implémenter tous les membres définis par les interfaces. Toutefois, si la classe de base contient un membre qui correspond à un membre d'interface, le membre de classe de base peut fonctionner comme l'implémentation du membre d'interface et vous n'êtes pas obligé de l'implémenter à nouveau manuellement.

Mehrdad Afshari
la source
1
Ouais ça marche! Pourquoi n'y ai-je pas pensé! Et aux commentaires ci-dessous. Merci de
m'éclairer
1
@Jordan, notez également que la classe de base et la liste des interfaces héritées sont séparées par des virgules après les deux points initiaux (exemple de @ Mehrdad).
JMD
1
pour développer un peu: si votre classe de base implémente l'interface, alors votre classe dérivée implémente automatiquement cette interface - même sans USBDevice : IOurDevice. L'ajout explicite de l'implémentation n'a pas d'impact sur la classe de base, mais cela peut aider à mettre l'accent sur l'interface.
STW
1
@David, même si vous ne vous trompez pas, ce n'est pas la terminologie qui empêchait le code de @ Jordan de fonctionner. C'était une syntaxe incorrecte.
JMD
2
+1 pour avoir également clarifié une question que je voulais poser concernant des membres identiques à la fois dans la base et dans l'interface.
Riegardt Steyn
21

Non, pas exactement. Mais il peut hériter d'une classe et implémenter une ou plusieurs interfaces.

Une terminologie claire est importante pour discuter de concepts comme celui-ci. L'une des choses que vous verrez marquer l'écriture de Jon Skeet, par exemple, à la fois ici et sur papier, est qu'il est toujours précis dans la façon dont il décrit les choses.

David M
la source
8
Ou Eric Lippert, dont l'écriture est très précise.
Mathias
21

Sans rapport avec la question (la réponse de Mehrdad devrait vous faire avancer), et j'espère que cela n'est pas considéré comme un pinailleux: les classes n'héritent pas des interfaces, elles implémentent .

.NET ne prend pas en charge l'héritage multiple, donc garder les termes droits peut aider à la communication. Une classe peut hériter d'une superclasse et implémenter autant d'interfaces qu'elle le souhaite.


En réponse au commentaire d'Eric ... j'ai eu une discussion avec un autre développeur sur la question de savoir si les interfaces "héritent", "implémentent", "exigent" ou "apportent" des interfaces avec une déclaration comme:

public interface ITwo : IOne

La réponse technique est que ITwocela hérite IOnepour plusieurs raisons:

  • Les interfaces n'ont jamais d'implémentation, donc en soutenant que ITwo implémente IOne sont complètement faux
  • ITwohérite des IOneméthodes, s'il MethodOne()existe surIOne il est également accessible depuis ITwo. ie: ((ITwo)someObject).MethodOne())est valide, même si ITwone contient pas explicitement de définition pourMethodOne()
  • ... parce que le runtime le dit! typeof(IOne).IsAssignableFrom(typeof(ITwo))Retourtrue

Nous avons finalement convenu que les interfaces prennent en charge l'héritage vrai / complet. Les fonctionnalités d'héritage manquantes (telles que les remplacements, les accesseurs abstraits / virtuels, etc.) sont absentes des interfaces, pas de l'héritage d'interface. Cela ne rend toujours pas le concept simple ou clair, mais cela aide à comprendre ce qui se passe vraiment sous le capot dans le monde d'Eric :-)

STW
la source
3
Cependant, malheureusement, les interfaces héritent d' autres interfaces. Je trouve ce choix de mots malheureux, mais nous nous y tenons maintenant. Je préfère penser aux interfaces comme nécessitant d' autres interfaces. C'est-à-dire que lorsque vous dites "interface IFoo: IBar", cela signifie "qu'un réalisateur d'IFoo doit également implémenter IBar".
Eric Lippert
@Eric Je suis d'accord que c'est un terme peu clair et j'en ai débattu avec un collègue il y a quelque temps. Finalement, nous avons décidé que dire "ITwo hérite de IOne". Je vais mettre à jour ma réponse avec quelques petites raisons (simplement parce qu'elles ne rentrent pas clairement dans un commentaire).
STW
Sûr; si vous définissez «A hérite de B» comme signifiant «les membres de B sont tous membres de A», alors les interfaces «héritent» des interfaces de base. C'est une définition raisonnable. Mais je préfère penser à «l'héritage» comme étant plus strictement non seulement le partage des membres abstraits et non implémentés , mais plutôt l'héritage des implémentations . Étant donné que les interfaces n'ont pas d'implémentation, je trouve quelque peu inquiétant de penser que les interfaces héritent de quoi que ce soit. C'est un point subtil et discutable.
Eric Lippert
Un autre terme que j'aime est "étendre". Vous pourriez donc lire "interface IFoo: IBar" pour signifier que IFoo étend les exigences d'IBar.
jasonh
1
@Joan: vous avez raison de dire que les classes implémentent (et ne peuvent pas hériter) des interfaces. Le point qu'Eric fait valoir est que les interfaces peuvent hériter d'autres interfaces - ce qui peut être un peu difficile à digérer étant donné que les interfaces ne sont que des «spécifications» plutôt que des implémentations.
STW
1

J'ai trouvé la réponse à la deuxième partie de mes questions. Oui, une classe peut implémenter une interface qui est dans une classe différente tant que l'interface est déclarée comme publique.

PICyourBrain
la source
Il n'est pas nécessaire que ce soit public dans tous les cas. Juste accessible. Par exemple class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, la MyExampleclasse implémente une interface privée imbriquée. Dans d'autres exemples, l'interface imbriquée (et la classe contenant) pourrait être internal. Tout dépend de qui a besoin de les utiliser et de s'en soucier.
Jeppe Stig Nielsen