Например, предположим, что мне нужен ICar
интерфейс, и что все реализации будут содержать поле Year
. Значит ли это, что каждая реализация должна декларировать отдельно Year
? Разве не было бы лучше просто определить это в интерфейсе?
223
Ответы:
Хотя многие другие ответы верны на семантическом уровне, я нахожу интересным также подойти к этим видам вопросов с уровня детализации реализации.
Интерфейс может рассматриваться как набор слотов , которые содержат методы . Когда класс реализует интерфейс, класс должен сообщить среде выполнения, как заполнить все необходимые слоты. Когда ты говоришь
класс говорит: «когда вы создаете мой экземпляр, вставьте ссылку на Foo.M в слот для IFoo.M.
Затем, когда вы делаете звонок:
компилятор генерирует код, который говорит: «спросите у объекта, какой метод находится в слоте для IFoo.M, и вызовите этот метод.
Если интерфейс представляет собой набор слотов, которые содержат методы, то некоторые из этих слотов могут также содержать методы получения и установки свойства, методы получения и установки индексатора, а также методы добавления и удаления события. Но поле это не метод . Нет никакого «слота», связанного с полем, которое вы можете затем «заполнить» ссылкой на местоположение поля. И поэтому интерфейсы могут определять методы, свойства, индексаторы и события, но не поля.
источник
An interface cannot contain constants, fields, operators
из msdn.microsoft.com/en-us/library/ms173156.aspx )int One()
, то реализацияpublic int One(){return 1;}
не является полем.Интерфейсы в C # предназначены для определения договора, которого будет придерживаться класс, а не конкретной реализации.
В этом духе интерфейсы C # позволяют определять свойства, которые вызывающая сторона должна предоставлять для реализации:
Реализующие классы могут использовать авто-свойства для упрощения реализации, если с этим свойством не связана специальная логика:
источник
Year
?public int Year => 123;
, Однако в этом случае нет смысла иметь установщик, поэтому интерфейс должен быть определен с помощьюint Year { get; }
Объявите это как собственность:
источник
Эрик Липперт прибил это, я буду использовать другой способ сказать то, что он сказал. Все члены интерфейса являются виртуальными, и все они должны быть переопределены классом, который наследует интерфейс. Вы не пишете явно ключевое слово virtual в объявлении интерфейса и не используете ключевое слово override в классе, они подразумеваются.
Виртуальное ключевое слово реализовано в .NET с методами и так называемой v-таблицей, массивом указателей на методы. Ключевое слово override заполняет слот v-таблицы другим указателем метода, перезаписывая тот, который создается базовым классом. Свойства, события и индексаторы реализованы как скрытые методы. Но поля нет. Поэтому интерфейсы могут не содержать полей.
источник
Почему бы просто не иметь
Year
собственность, которая идеально подходит?Интерфейсы не содержат полей, потому что поля представляют собой конкретную реализацию представления данных, и предоставление их нарушило бы инкапсуляцию. Таким образом, наличие интерфейса с полем будет эффективно кодировать реализацию, а не интерфейс, что является странным парадоксом для интерфейса!
Например, часть вашей
Year
спецификации может потребовать, чтобы дляICar
разработчиков было недопустимо разрешать присваивание a,Year
которое позже текущего года + 1 или до 1900 года. Нельзя сказать, что если вы выставилиYear
поля - гораздо лучше использовать свойства вместо того, чтобы делать работу здесь.источник
Короткий ответ - да, каждый тип реализации должен будет создать собственную переменную поддержки. Это потому, что интерфейс аналогичен контракту. Все, что он может сделать, это указать конкретные общедоступные фрагменты кода, которые должен сделать доступным тип реализации; он не может содержать сам код.
Рассмотрите этот сценарий, используя то, что вы предлагаете:
У нас есть пара проблем здесь:
myBackingVariable
будетMyClass
использовать?Наиболее распространенный подход заключается в объявлении интерфейса и базового абстрактного класса, который его реализует. Это позволяет вам гибко либо наследовать от абстрактного класса и получать реализацию бесплатно, либо явно реализовывать интерфейс и получать наследование от другого класса. Это работает примерно так:
источник
Другие задали «почему», поэтому я просто добавлю, что ваш интерфейс может определять элемент управления; если вы заверните это в свойство:
источник
Интерфейсы не содержат никакой реализации.
источник
Много уже сказано, но для простоты вот мое мнение. Предполагается, что интерфейсы имеют контракты методов, которые должны быть реализованы потребителями или классами, а не поля для хранения значений.
Вы можете поспорить, что тогда почему свойства разрешены? Таким образом, простой ответ - свойства определены внутри только как методы.
источник
Для этого у вас может быть базовый класс Car, который реализует поле year, и все другие реализации могут наследовать его.
источник
Интерфейс определяет общедоступные свойства и методы экземпляра. Поля, как правило, являются частными или, как правило, наиболее защищенными, внутренними или защищенными внутренними (термин «поле» обычно не используется ни для каких общедоступных).
Как указано в других ответах, вы можете определить базовый класс и определить защищенное свойство, которое будет доступно всем наследникам.
Одна странность состоит в том, что интерфейс может фактически быть определен как внутренний, но он ограничивает полезность интерфейса, и он обычно используется для определения внутренней функциональности, которая не используется другим внешним кодом.
источник