En C #, ¿puede una clase heredar de otra clase y una interfaz?

130

Quiero saber si una clase puede heredar de una clase y una interfaz. El siguiente código de ejemplo no funciona, pero creo que transmite lo que quiero hacer. La razón por la que quiero hacer esto es porque en mi empresa fabricamos dispositivos USB, seriales, Ethernet, etc. Estoy tratando de desarrollar un componente / interfaz genérico que pueda usar para escribir programas para todos nuestros dispositivos que ayuden a mantener las cosas comunes (como conectar, desconectar, obtener firmware) igual para todas nuestras aplicaciones.

Para agregar a esta pregunta: si GenericDevice está en un proyecto diferente, ¿puedo poner la interfaz IOurDevices en ese proyecto y luego hacer que la clase USBDevice implemente la interfaz si agrego una referencia al primer proyecto? Porque me gustaría simplemente hacer referencia a un proyecto y luego implementar diferentes interfaces según el 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;
   }
}
PICyourBrain
fuente
55
Para su referencia futura, la sección 10.1.4 de la especificación de C # describe con precisión cómo declarar una clase que tiene múltiples tipos base.
Eric Lippert el
@Eric Lippert: ¿Podrían ayudarme a comprender este caso si es correcto y estará disponible en el futuro?
Gul Md Ershad

Respuestas:

246

Si. Tratar:

class USBDevice : GenericDevice, IOurDevice

Nota: La clase base debe aparecer antes de la lista de nombres de interfaz.

Por supuesto, aún necesitará implementar todos los miembros que definen las interfaces. Sin embargo, si la clase base contiene un miembro que coincide con un miembro de la interfaz, el miembro de la clase base puede funcionar como la implementación del miembro de la interfaz y no es necesario que lo implemente manualmente nuevamente.

Mehrdad Afshari
fuente
1
Sí, esto funciona! ¿Por qué no pensé en eso? Y a los comentarios a continuación. Gracias por
aclararme
1
@ Jordan, también tenga en cuenta que la clase base y la lista de interfaces que se heredan están separadas por comas después de los dos puntos iniciales (ejemplo de @ Mehrdad).
JMD
1
expandir solo un poco: si su clase base implementa la interfaz, entonces su clase derivada implementa automáticamente esa interfaz, incluso sin ella USBDevice : IOurDevice. Agregar la implementación explícitamente no afecta la clase base, pero puede ayudar a poner énfasis en la interfaz.
STW
1
@David, aunque no estás equivocado, no fue la terminología lo que impidió que el código de @ Jordan funcionara. Era una sintaxis incorrecta.
JMD
2
+1 por aclarar también una pregunta que quería hacer con respecto a miembros idénticos tanto en la Base como en la Interfaz.
Riegardt Steyn
21

No, no exactamente Pero puede heredar de una clase e implementar una o más interfaces.

Una terminología clara es importante cuando se discuten conceptos como este. Una de las cosas que verá marcan la escritura de Jon Skeet, por ejemplo, tanto aquí como en forma impresa, es que siempre es preciso en la forma en que describe las cosas.

David M
fuente
8
O Eric Lippert, cuya escritura es muy precisa.
Mathias el
21

Sin relación con la pregunta (la respuesta de Mehrdad debería ayudarlo), y espero que esto no se tome como algo quisquilloso: las clases no heredan las interfaces, las implementan .

.NET no admite la herencia múltiple, por lo que mantener los términos correctos puede ayudar en la comunicación. Una clase puede heredar de una superclase y puede implementar tantas interfaces como desee.


En respuesta al comentario de Eric ... Tuve una discusión con otro desarrollador sobre si las interfaces "heredan", "implementan", "requieren" o "traen" interfaces con una declaración como:

public interface ITwo : IOne

La respuesta técnica es que ITwohereda IOnepor algunas razones:

  • Las interfaces nunca tienen una implementación, por lo que argumentar que los ITwo implementos IOne es completamente incorrecto
  • ITwohereda IOnemétodos, si MethodOne()existe, IOneentonces también es accesible desde ITwo. es decir: ((ITwo)someObject).MethodOne())es válido, aunque ITwono contiene explícitamente una definición paraMethodOne()
  • ... porque el tiempo de ejecución lo dice! typeof(IOne).IsAssignableFrom(typeof(ITwo))devolucionestrue

Finalmente acordamos que las interfaces admiten herencia verdadera / completa. Las características de herencia faltantes (como anulaciones, accesos abstractos / virtuales, etc.) faltan en las interfaces, no en la herencia de la interfaz. Todavía no hace que el concepto sea simple o claro, pero ayuda a comprender lo que realmente está sucediendo bajo el capó en el mundo de Eric :-)

STW
fuente
3
Aunque, desafortunadamente, las interfaces heredan otras interfaces. Me parece desafortunada esa elección de palabras, pero ahora estamos atrapados en ella. Prefiero pensar que las interfaces requieren otras interfaces. Es decir, cuando dice "interfaz IFoo: IBar", eso significa "se requiere un implementador de IFoo para implementar también IBar".
Eric Lippert el
@Eric Estoy de acuerdo en que es un término poco claro y lo debatí con un colega hace un tiempo. Al final decidimos que decir "ITwo hereda IOne". Actualizaré mi respuesta con un par de pequeñas razones (solo porque no caben claramente en un comentario).
STW
Por supuesto; si define "A hereda de B" como "todos los miembros de B son miembros de A", las interfaces "heredan" de las interfaces base. Esta es una definición razonable. Pero prefiero pensar que la "herencia" se trata más estrictamente de no solo compartir los miembros abstractos y no implementados, sino de heredar implementaciones . Como las interfaces no tienen implementaciones, me resulta un tanto inquietante pensar que las interfaces heredan de cualquier cosa. Es un punto sutil y discutible.
Eric Lippert el
Otro término que me gusta es "extender". Por lo tanto, podría leer "interfaz IFoo: IBar" para indicar que IFoo extiende los requisitos de IBar.
jasonh
1
@Joan: tienes razón en que las clases implementan (y no pueden heredar) interfaces. El punto de Eric es que las interfaces pueden heredar otras interfaces, lo que puede ser algo difícil de digerir dado que las interfaces son solo "especificaciones" en lugar de implementaciones.
STW
1

Encontré la respuesta a la segunda parte de mis preguntas. Sí, una clase puede implementar una interfaz que está en una clase diferente siempre que la interfaz se declare como pública.

PICyourBrain
fuente
No tiene que ser público en todos los casos. Solo accesible. Por ejemplo class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, la MyExampleclase implementa una interfaz privada anidada. En otros ejemplos, la interfaz anidada (y la clase que lo contiene) podría ser internal. Todo depende de quién necesite usarlos y molestarse con ellos.
Jeppe Stig Nielsen