В C # может ли класс наследовать от другого класса и интерфейса?

130

Я хочу знать, может ли класс наследовать от класса и интерфейса. Приведенный ниже пример кода не работает, но я думаю, что он передает то, что я хочу сделать. Причина, по которой я хочу это сделать, заключается в том, что в моей компании мы производим устройства USB, последовательного порта, Ethernet и т. Д. Я пытаюсь разработать общий компонент / интерфейс, который я могу использовать для написания программ для всех наших устройств, которые помогут сохранить общие вещи (например, подключение, отключение, получение прошивки) одинаковыми для всех наших приложений.

Чтобы добавить к этому вопросу: если GenericDevice находится в другом проекте, могу ли я поместить интерфейс IOurDevices в этот проект, а затем заставить класс USBDevice реализовать интерфейс, если я добавлю ссылку на первый проект? Потому что хотелось бы просто сослаться на один проект, а затем реализовать разные интерфейсы в зависимости от устройства.

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
источник
5
Для справки в будущем раздел 10.1.4 спецификации C # точно описывает, как объявить класс, имеющий несколько базовых типов.
Эрик Липперт,
@Eric Lippert: Не могли бы вы помочь мне разобраться в этом случае, верен ли он и будет ли он доступен в будущем?
Gul Md Ershad

Ответы:

246

Да. Пытаться:

class USBDevice : GenericDevice, IOurDevice

Примечание . Базовый класс должен стоять перед списком имен интерфейсов.

Конечно, вам все равно нужно будет реализовать все члены, определяемые интерфейсами. Однако, если базовый класс содержит член, который соответствует члену интерфейса, член базового класса может работать как реализация члена интерфейса, и вам не нужно вручную реализовывать его снова.

Мехрдад Афшари
источник
1
Ага, это работает! Почему я не подумал об этом! И к комментариям ниже. Спасибо, что разъяснили мне это (классы не наследуют интерфейсы, интерфейсы IMPLEMENT)
PICyourBrain
1
@Jordan, также обратите внимание, что базовый класс и список наследуемых интерфейсов разделяются запятыми после начального двоеточия (пример @ Mehrdad).
JMD
1
чтобы немного расширить: если ваш базовый класс реализует интерфейс, то производный класс автоматически реализует этот интерфейс - даже без USBDevice : IOurDevice. Явное добавление реализации не влияет на базовый класс, но может помочь сделать акцент на интерфейсе.
STW
1
@ Дэвид, вы не ошиблись, но не терминология мешала работе кода @Jordan. Это был неправильный синтаксис.
JMD
2
+1 за то, что также прояснил вопрос, который я хотел задать относительно идентичных членов как в Базе, так и в Интерфейсе.
Riegardt Steyn 08
21

Нет, не совсем так. Но он может наследовать от класса и реализовывать один или несколько интерфейсов.

При обсуждении подобных понятий важна четкая терминология. Одна из особенностей письма Джона Скита, например, здесь и в печати, заключается в том, что он всегда точно описывает вещи.

Дэвид М
источник
8
Или Эрик Липперт, чей текст очень точен.
Матиас
21

Не имеет отношения к вопросу (ответ Мердада должен вас заинтересовать), и я надеюсь, что это не будет воспринято как мелочь: классы не наследуют интерфейсы, они их реализуют .

.NET не поддерживает множественное наследование, поэтому ясность терминов может помочь в общении. Класс может наследовать от одного суперкласса и может реализовывать столько интерфейсов, сколько пожелает.


В ответ на комментарий Эрика ... У меня было обсуждение с другим разработчиком о том, «наследуют» ли интерфейсы, «реализуют», «требуют» или «переносят» интерфейсы с таким объявлением, как:

public interface ITwo : IOne

Технический ответ заключается в том, что ITwoэто наследуется IOneпо нескольким причинам:

  • Интерфейсы никогда не имеют реализации, поэтому утверждать, что ITwo инструменты IOne плоские, неверно
  • ITwoнаследует IOneметоды, если MethodOne()существует, IOneто он также доступен из ITwo. т.е.: ((ITwo)someObject).MethodOne())действительно, хотя ITwoявно не содержит определения дляMethodOne()
  • ... потому что среда выполнения так говорит! typeof(IOne).IsAssignableFrom(typeof(ITwo))возвращаетсяtrue

Наконец мы договорились, что интерфейсы поддерживают истинное / полное наследование. Отсутствующие функции наследования (такие как переопределения, абстрактные / виртуальные средства доступа и т. Д.) Отсутствуют в интерфейсах, а не в наследовании интерфейсов. Это все еще не делает концепцию простой или ясной, но помогает понять, что на самом деле происходит под капотом в мире Эрика :-)

STW
источник
3
Хотя, к сожалению, интерфейсы наследуют другие интерфейсы. Я считаю такой выбор слов неудачным, но сейчас мы застряли на нем. Я предпочитаю думать, что интерфейсы требуют других интерфейсов. То есть, когда вы говорите «интерфейс IFoo: IBar», это означает, что «разработчик IFoo должен также реализовать IBar».
Эрик Липперт,
@Eric Я согласен, что это непонятный термин, и некоторое время назад обсуждал его с коллегой. В конце концов мы решили, что поговорка «ITwo наследует IOne». Я дополню свой ответ парой небольших причин (просто потому, что они не вписываются в комментарий).
STW
Конечно; если вы определяете «A наследуется от B» как означающее «все члены B являются членами A», то интерфейсы действительно «наследуются» от базовых интерфейсов. Это разумное определение. Но я предпочитаю думать о «наследовании» как о более строгом понимании не только совместного использования абстрактных, нереализованных членов, но, скорее, наследования реализаций . Поскольку интерфейсы не имеют реализаций, мне несколько неприятно думать об интерфейсах как об унаследованных от чего-либо. Это тонкий и спорный момент.
Эрик Липперт,
Еще один термин, который мне нравится, - «продлить». Таким образом, вы можете прочитать «interface IFoo: IBar», чтобы обозначить, что IFoo расширяет требования IBar.
jasonh
1
@Joan: вы правы, что классы реализуют (и не могут наследовать) интерфейсы. Эрик подчеркивает, что интерфейсы могут наследовать другие интерфейсы, что может быть довольно сложно переварить, учитывая, что интерфейсы являются только «спецификациями», а не реализациями.
STW
1

Я нашел ответ на вторую часть своих вопросов. Да, класс может реализовать интерфейс, принадлежащий другому классу, если интерфейс объявлен как открытый.

PICyourBrain
источник
Это не обязательно должно быть публичным во всех случаях. Просто доступно. Например class ContainsAll { private interface INested { /* ... */ } private class MyExample : INested { /* ... */ } }, MyExampleкласс реализует вложенный частный интерфейс. В других примерах вложенный интерфейс (и содержащий его класс) может быть internal. Все зависит от того, кому нужно их использовать и возиться с ними.
Jeppe Stig Nielsen