Em C #, uma classe pode herdar de outra classe e uma interface?

130

Eu quero saber se uma classe pode herdar de uma classe e uma interface. O código de exemplo abaixo não funciona, mas acho que ele transmite o que quero fazer. A razão pela qual eu quero fazer isso é porque, na minha empresa, fabricamos dispositivos USB, serial, Ethernet, etc. Estou tentando desenvolver um componente / interface genérico que possa ser usado para escrever programas para todos os nossos dispositivos que ajudarão a manter as coisas comuns (como conectar, desconectar, obter firmware) iguais para todos os nossos aplicativos.

Para adicionar a esta pergunta: Se GenericDevice estiver em um projeto diferente, posso colocar a interface IOurDevices nesse projeto e fazer com que a classe USBDevice implemente a interface se adicionar uma referência ao primeiro projeto? Porque gostaria de referenciar apenas um projeto e, em seguida, implementar interfaces diferentes, dependendo do 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
fonte
5
Para referência futura, a seção 10.1.4 da especificação C # descreve precisamente como declarar uma classe que possui vários tipos de base.
Eric Lippert
@ Eric Lippert: Você poderia me ajudar a entender sobre este caso se é o caminho correto e estará disponível no futuro?
Gul Md Ershad

Respostas:

246

Sim. Experimentar:

class USBDevice : GenericDevice, IOurDevice

Nota: A classe base deve vir antes da lista de nomes de interface.

Obviamente, você ainda precisará implementar todos os membros que as interfaces definem. No entanto, se a classe base contiver um membro que corresponda a um membro da interface, ele poderá funcionar como a implementação do membro da interface e você não precisará implementá-lo manualmente novamente.

Mehrdad Afshari
fonte
1
Sim, isso funciona! Por que eu não pensei nisso! E para os comentários abaixo. Obrigado por me esclarecer em que (Classes que interfaces não herdar, a interfaces de IMPLEMENTAR)
PICyourBrain
1
@ Jordânia, observe também que a classe base e a lista de interfaces herdadas são separadas por vírgulas após os dois pontos iniciais (exemplo de @ Mehrdad).
JMD
1
para expandir um pouco: se sua classe base implementa a interface, sua classe derivada implementa automaticamente essa interface - mesmo sem ela USBDevice : IOurDevice. Adicionar a implementação explicitamente não afeta a classe base, mas pode ajudar a colocar ênfase na interface.
STW
1
@ David, enquanto você não está errado, não era a terminologia que estava impedindo o código do @ Jordan de funcionar. A sintaxe estava incorreta.
JMD
2
+1 por esclarecer uma pergunta que eu queria fazer sobre membros idênticos na Base e na Interface.
Riegardt Steyn
21

Não exatamente. Mas pode herdar de uma classe e implementar uma ou mais interfaces.

Uma terminologia clara é importante ao discutir conceitos como este. Uma das coisas que você verá marcar os escritos de Jon Skeet, por exemplo, aqui e na imprensa, é que ele é sempre preciso na maneira como descreve as coisas.

David M
fonte
8
Ou Eric Lippert, cuja escrita é muito precisa.
Mathias
21

Sem relação com a pergunta (a resposta de Mehrdad deve ajudá-lo), e espero que isso não seja entendido: as classes não herdam interfaces, elas as implementam .

O .NET não suporta herança múltipla, portanto, manter os termos corretos pode ajudar na comunicação. Uma classe pode herdar de uma superclasse e implementar quantas interfaces desejar.


Em resposta ao comentário de Eric ... tive uma discussão com outro desenvolvedor sobre se as interfaces "herdam", "implementam", "exigem" ou "trazem" interfaces com uma declaração como:

public interface ITwo : IOne

A resposta técnica é que ITwoherda IOnepor alguns motivos:

  • As interfaces nunca têm uma implementação, então argumentar que ITwo implementa IOne é totalmente errado
  • ITwoherda IOnemétodos, se MethodOne()existir IOne, também é acessível a partir de ITwo. ie: ((ITwo)someObject).MethodOne())é válido, mesmo que ITwonão contenha explicitamente uma definição paraMethodOne()
  • ... porque o tempo de execução diz isso! typeof(IOne).IsAssignableFrom(typeof(ITwo))retornatrue

Finalmente concordamos que as interfaces suportam herança verdadeira / completa. Os recursos de herança ausentes (como substituições, acessadores abstratos / virtuais etc.) estão ausentes nas interfaces, não na herança da interface. Ainda não torna o conceito simples ou claro, mas ajuda a entender o que realmente está acontecendo no mundo de Eric :-)

STW
fonte
3
Embora, infelizmente, as interfaces herdam outras interfaces. Acho essa escolha de palavras infeliz, mas estamos presos a ela agora. Prefiro pensar nas interfaces como exigindo outras interfaces. Ou seja, quando você diz "interface IFoo: IBar" que significa "é necessário um implementador do IFoo para implementar o IBar".
Eric Lippert
@ Eric Concordo que é um termo pouco claro e o debati com um colega há algum tempo. No final, decidimos que dizer "ITwo herda IOne". Atualizarei minha resposta com algumas pequenas razões (apenas porque elas não se encaixam claramente em um comentário).
STW
Certo; se você definir "A herda de B" como significando "membros de B são todos membros de A", as interfaces serão "herdadas" das interfaces de base. Esta é uma definição razoável. Mas prefiro pensar em "herança" como sendo mais estritamente não apenas compartilhar os membros abstratos e não implementados, mas sim, herdar implementações . Como as interfaces não têm implementações, acho um pouco preocupante pensar nas interfaces como herdadas de qualquer coisa. É um ponto sutil e discutível.
Eric Lippert
Outro termo que eu gosto é "estender". Então você pode ler "interface IFoo: IBar" para significar que o IFoo estende os requisitos do IBar.
jasonh
1
@ Joan: você está certo de que as classes implementam (e não podem herdar) interfaces. O argumento de Eric é que as interfaces podem herdar outras - o que pode ser um pouco difícil de digerir, já que as interfaces são apenas "especificações" e não implementações.
STW
1

Encontrei a resposta para a segunda parte das minhas perguntas. Sim, uma classe pode implementar uma interface que esteja em uma classe diferente, desde que a interface seja declarada como pública.

PICyourBrain
fonte
Não precisa ser público em todos os casos. Apenas acessível. Por exemplo class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, a MyExampleclasse implementa uma interface privada aninhada. Em outros exemplos, a interface aninhada (e a classe que contém) poderia ser internal. Tudo depende de quem precisa usá-los e se preocupar com eles.
Jeppe Stig Nielsen