Kann eine Klasse in C # von einer anderen Klasse und einer Schnittstelle erben?

130

Ich möchte wissen, ob eine Klasse von einer Klasse und einer Schnittstelle erben kann. Der folgende Beispielcode funktioniert nicht, aber ich denke, er vermittelt, was ich tun möchte. Der Grund, warum ich dies tun möchte, ist, dass wir in meinem Unternehmen USB-, serielle, Ethernet- usw. Geräte herstellen. Ich versuche, eine generische Komponente / Schnittstelle zu entwickeln, mit der ich Programme für alle unsere Geräte schreiben kann, die dazu beitragen, dass die allgemeinen Dinge (wie Verbinden, Trennen, Abrufen der Firmware) für alle unsere Anwendungen gleich bleiben.

So fügen Sie dieser Frage hinzu: Wenn sich GenericDevice in einem anderen Projekt befindet, kann ich die IOurDevices-Schnittstelle in dieses Projekt einfügen und dann die USBDevice-Klasse veranlassen, die Schnittstelle zu implementieren, wenn ich einen Verweis auf das erste Projekt hinzufüge? Denn ich möchte nur auf ein Projekt verweisen und dann je nach Gerät unterschiedliche Schnittstellen implementieren.

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
quelle
5
Für Ihre zukünftige Referenz beschreibt Abschnitt 10.1.4 der C # -Spezifikation genau, wie eine Klasse mit mehreren Basistypen deklariert wird.
Eric Lippert
@ Eric Lippert: Könnten Sie mir bitte helfen, diesen Fall zu verstehen, ob er korrekt ist und in Zukunft verfügbar sein wird?
Gul Md Ershad

Antworten:

244

Ja. Versuchen:

class USBDevice : GenericDevice, IOurDevice

Hinweis: Die Basisklasse sollte vor der Liste der Schnittstellennamen stehen.

Natürlich müssen Sie immer noch alle Mitglieder implementieren, die die Schnittstellen definieren. Wenn die Basisklasse jedoch ein Element enthält, das einem Schnittstellenmitglied entspricht, kann das Basisklassenmitglied als Implementierung des Schnittstellenelements fungieren, und Sie müssen es nicht erneut manuell implementieren.

Mehrdad Afshari
quelle
1
Ja das funktioniert! Warum habe ich nicht daran gedacht! Und zu den Kommentaren unten. Vielen Dank, dass Sie mich darüber aufgeklärt haben (Klassen erben keine Schnittstellen, die IMPLEMENT-Schnittstellen)
PICyourBrain
1
@Jordan, beachten Sie auch, dass die Basisklasse und die Liste der geerbten Schnittstellen nach dem Anfangsbuchstaben durch Kommas getrennt sind (Beispiel von @ Mehrdad).
JMD
1
Um es nur ein wenig zu erweitern: Wenn Ihre Basisklasse die Schnittstelle implementiert, implementiert Ihre abgeleitete Klasse diese Schnittstelle automatisch - auch ohne USBDevice : IOurDevice. Das explizite Hinzufügen der Implementierung wirkt sich nicht auf die Basisklasse aus, kann jedoch dazu beitragen, die Schnittstelle hervorzuheben.
STW
1
@ David, obwohl Sie sich nicht irren, war es nicht die Terminologie, die @ Jordans Code daran hinderte, zu funktionieren. Es war eine falsche Syntax.
JMD
2
+1, um auch eine Frage zu klären, die ich zu identischen Mitgliedern sowohl in der Basis als auch in der Schnittstelle stellen wollte.
Riegardt Steyn
20

Nein, nicht genau. Aber es kann von einer Klasse erben und implementieren eine oder mehrere Schnittstellen.

Eine klare Terminologie ist wichtig, wenn solche Konzepte diskutiert werden. Eines der Dinge, die Sie sehen werden, wie Jon Skeet zum Beispiel hier und in gedruckter Form schreibt, ist, dass er immer präzise in der Art ist, wie er Dinge beschreibt.

David M.
quelle
8
Oder Eric Lippert, dessen Schrift sehr genau ist.
Mathias
20

Unabhängig von der Frage (Mehrdads Antwort sollte Sie zum Laufen bringen), und ich hoffe, dass dies nicht als pingelig angesehen wird: Klassen erben keine Schnittstellen, sie implementieren sie.

.NET unterstützt keine Mehrfachvererbung, daher kann es bei der Kommunikation hilfreich sein, die Begriffe klar zu halten. Eine Klasse kann von einer Oberklasse erben und so viele Schnittstellen implementieren, wie sie möchte.


Als Antwort auf Erics Kommentar ... hatte ich eine Diskussion mit einem anderen Entwickler darüber, ob Schnittstellen Schnittstellen mit einer Deklaration wie "erben", "implementieren", "erfordern" oder "mitbringen".

public interface ITwo : IOne

Die technische Antwort lautet: ITwoErbt IOneaus mehreren Gründen:

  • Schnittstellen haben nie eine Implementierung, daher ist es völlig falsch zu argumentieren, dass ITwo Implementierungen IOne völlig falsch sind
  • ITwoerbt IOneMethoden, wenn MethodOne()vorhanden, IOnedann ist es auch zugänglich von ITwo. dh: ((ITwo)someObject).MethodOne())ist gültig, obwohl ITwoes keine explizite Definition für enthältMethodOne()
  • ... weil die Laufzeit es sagt! typeof(IOne).IsAssignableFrom(typeof(ITwo))kehrt zurücktrue

Wir waren uns schließlich einig, dass Schnittstellen echte / vollständige Vererbung unterstützen. Die fehlenden Vererbungsfunktionen (wie Überschreibungen, abstrakte / virtuelle Accessoren usw.) fehlen in Schnittstellen, nicht in der Schnittstellenvererbung. Es macht das Konzept immer noch nicht einfach oder klar, aber es hilft zu verstehen, was in Erics Welt wirklich unter der Haube vor sich geht :-)

STW
quelle
3
Leider erben Schnittstellen andere Schnittstellen. Ich finde diese Wortwahl unglücklich, aber wir bleiben jetzt dabei. Ich ziehe es von Schnittstellen zu denken , wie erfordern andere Schnittstellen. Das heißt, wenn Sie "Schnittstelle IFoo: IBar" sagen, bedeutet dies, dass "ein Implementierer von IFoo erforderlich ist, um auch IBar zu implementieren".
Eric Lippert
@ Eric Ich stimme zu, dass es ein unklarer Begriff ist und habe ihn vor einiger Zeit mit einem Kollegen diskutiert. Am Ende haben wir beschlossen, dass "ITwo IOne erbt". Ich werde meine Antwort mit ein paar kleinen Gründen aktualisieren (nur weil sie nicht eindeutig in einen Kommentar passen).
STW
Sicher; Wenn Sie "A erbt von B" als "Mitglieder von B sind alle Mitglieder von A" definieren, "erben" Schnittstellen von Basisschnittstellen. Dies ist eine vernünftige Definition. Aber ich ziehe es vor, bei "Vererbung" strenger zu sein, nicht nur die abstrakten, nicht implementierten Mitglieder zu teilen, sondern Implementierungen zu erben . Da Schnittstellen keine Implementierungen haben, finde ich es etwas beunruhigend, sich Schnittstellen als Erben von irgendetwas vorzustellen. Es ist ein subtiler und umstrittener Punkt.
Eric Lippert
Ein anderer Begriff, den ich mag, ist "verlängern". Sie könnten also "Schnittstelle IFoo: IBar" lesen, um zu bedeuten, dass IFoo die Anforderungen von IBar erweitert.
Jason
1
@Joan: Sie haben Recht, dass Klassen Schnittstellen implementieren (und nicht erben können). Der Punkt, den Eric hervorhebt, ist, dass Schnittstellen andere Schnittstellen erben können - was etwas schwer zu verdauen sein kann, da Schnittstellen nur "Spezifikationen" und keine Implementierungen sind.
STW
1

Ich fand die Antwort auf den zweiten Teil meiner Fragen. Ja, eine Klasse kann eine Schnittstelle implementieren, die sich in einer anderen Klasse befindet, solange die Schnittstelle als öffentlich deklariert ist.

PICyourBrain
quelle
Es muss nicht in allen Fällen öffentlich sein. Einfach zugänglich. Beispielsweise implementiert class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }die MyExampleKlasse eine verschachtelte private Schnittstelle. In anderen Beispielen könnte die verschachtelte Schnittstelle (und die enthaltende Klasse) sein internal. Es hängt alles davon ab, wer sie verwenden und sich um sie kümmern muss.
Jeppe Stig Nielsen