In C #, una classe può ereditare da un'altra classe e un'interfaccia?


130

Voglio sapere se una classe può ereditare da una classe e un'interfaccia. Il codice di esempio che segue non funziona ma penso che trasmetta ciò che voglio fare. Il motivo per cui voglio farlo è perché nella mia azienda realizziamo dispositivi USB, seriali, Ethernet, ecc. Sto cercando di sviluppare un componente / un'interfaccia generica che posso usare per scrivere programmi per tutti i nostri dispositivi che contribuiranno a mantenere le cose comuni (come la connessione, la disconnessione, il recupero del firmware) lo stesso per tutte le nostre applicazioni.

Per aggiungere a questa domanda: Se GenericDevice si trova in un progetto diverso, posso inserire l'interfaccia IOurDevices in quel progetto, quindi fare in modo che la classe USBDevice implementi l'interfaccia se aggiungo un riferimento al primo progetto? Perché vorrei solo fare riferimento a un progetto e quindi implementare interfacce diverse a seconda di quale sia il dispositivo.

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;
   }
}

5
Per riferimento futuro, la sezione 10.1.4 della specifica C # descrive esattamente come dichiarare una classe che ha più tipi di base.
Eric Lippert,

@Eric Lippert: La prego di aiutarmi a capire su questo caso se è il modo corretto e sarà disponibile in futuro?
Gul Md Ershad,

Risposte:


246

Sì. Provare:

class USBDevice : GenericDevice, IOurDevice

Nota: la classe base dovrebbe precedere l'elenco dei nomi delle interfacce.

Ovviamente, dovrai comunque implementare tutti i membri definiti dalle interfacce. Tuttavia, se la classe base contiene un membro che corrisponde a un membro dell'interfaccia, il membro della classe base può funzionare come implementazione del membro dell'interfaccia e non è necessario implementarlo di nuovo manualmente.


1
Sì, questo funziona! Perché non ci ho pensato! E ai commenti qui sotto. Grazie per avermi
chiarito

1
@Jordan, nota anche che la classe base e l'elenco delle interfacce ereditate sono separati da virgole dopo i due punti iniziali (esempio di @ Mehrdad).
JMD,

1
per espandersi un po ': se la tua classe base implementa l'interfaccia, la tua classe derivata implementa automaticamente quell'interfaccia, anche senza USBDevice : IOurDevice. L'aggiunta esplicita dell'implementazione non influisce sulla classe di base, ma può aiutare a porre l'accento sull'interfaccia.
STW,

1
@David, anche se non sbagli, non era la terminologia che impediva il funzionamento del codice @ Jordan. Sintassi errata.
JMD,

2
+1 per chiarire anche una domanda che volevo porre riguardo a membri identici sia nella Base che nell'interfaccia.
Riegardt Steyn,

21

No, non esattamente. Ma può ereditare da una classe e implementare una o più interfacce.

La terminologia chiara è importante quando si discute di concetti come questo. Una delle cose che vedrai segnare la scrittura di Jon Skeet, ad esempio, sia qui che in stampa, è che è sempre preciso nel modo in cui descrive le cose.


8
O Eric Lippert, la cui scrittura è molto accurata.
Mathias,

21

Non correlato alla domanda (la risposta di Mehrdad dovrebbe farti andare avanti), e spero che questo non sia preso come pignolo: le classi non ereditano le interfacce, le implementano .

.NET non supporta l'ereditarietà multipla, quindi mantenere i termini chiari può aiutare nella comunicazione. Una classe può ereditare da una superclasse e può implementare tutte le interfacce che desidera.


In risposta al commento di Eric ... Ho avuto una discussione con un altro sviluppatore sull'interfaccia di "ereditare", "implementare", "richiedere" o "portare" interfacce con una dichiarazione del tipo:

public interface ITwo : IOne

La risposta tecnica è che ITwoeredita IOneper alcuni motivi:

  • Le interfacce non hanno mai un'implementazione, quindi sostenendo che ITwo implementa IOne sono completamente sbagliati
  • ITwoeredita i IOnemetodi, se MethodOne()esiste su IOneallora è anche accessibile da ITwo. vale a dire: ((ITwo)someObject).MethodOne())è valido, anche se ITwonon contiene esplicitamente una definizione perMethodOne()
  • ... perché lo dice il runtime! typeof(IOne).IsAssignableFrom(typeof(ITwo))ritornatrue

Abbiamo infine concordato che le interfacce supportano l'ereditarietà vera / completa. Le funzionalità di ereditarietà mancanti (come le sostituzioni, gli accessi astratti / virtuali, ecc.) Mancano dalle interfacce, non dall'ereditarietà dell'interfaccia. Non rende ancora il concetto semplice o chiaro, ma aiuta a capire cosa sta realmente succedendo sotto il cofano nel mondo di Eric :-)


3
Tuttavia, sfortunatamente, le interfacce ereditano altre interfacce. Trovo sfortunata quella scelta di parole, ma ora ci siamo bloccati. Preferisco pensare alle interfacce come se richiedessero altre interfacce. Cioè, quando si dice "interfaccia IFoo: IBar" che significa "è necessario un implementatore di IFoo per implementare anche IBar".
Eric Lippert,

@Eric Sono d'accordo che è un termine poco chiaro e ne ho discusso con un collega qualche tempo fa. Alla fine abbiamo deciso che dicendo "ITwo eredita IOne". Aggiornerò la mia risposta con un paio di piccoli motivi (solo perché non rientrano chiaramente in un commento).
STW,

Sicuro; se si definisce "A eredita da B" nel senso che "i membri di B sono tutti membri di A", le interfacce "ereditano" dalle interfacce di base. Questa è una definizione ragionevole. Ma preferisco pensare all '"eredità" come più strettamente non solo per condividere i membri astratti e non implementati, ma piuttosto per ereditare le implementazioni . Poiché le interfacce non hanno implementazioni, trovo alquanto inquietante pensare alle interfacce come ereditarie da qualsiasi cosa. È un punto sottile e discutibile.
Eric Lippert,

Un altro termine che mi piace è "estendere". Quindi potresti leggere "interfaccia IFoo: IBar" per indicare che IFoo estende i requisiti di IBar.
Jasonh,

1
@Joan: hai ragione che le classi implementano (e non possono ereditare) le interfacce. Il punto che Eric sottolinea è che le interfacce possono ereditare altre interfacce, il che può essere un po 'difficile da digerire dato che le interfacce sono solo "specifiche" piuttosto che implementazioni.
STW,

1

Ho trovato la risposta alla seconda parte delle mie domande. Sì, una classe può implementare un'interfaccia che si trova in una classe diversa purché l'interfaccia sia dichiarata pubblica.


Non deve essere pubblico in tutti i casi. Appena accessibile. Ad esempio class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, la MyExampleclasse implementa un'interfaccia privata nidificata. In altri esempi, l'interfaccia nidificata (e la classe contenente) potrebbe essere internal. Tutto dipende da chi ha bisogno di usarli e preoccuparsi di loro.
Jeppe Stig Nielsen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.