Зачем ставить перед именами интерфейсов C# букву «I»

Каково обоснование этого соглашения об именах?

Я не вижу никакой пользы. Дополнительный префикс просто загрязняет API.

Мои мысли совпадают с ответом Конрада на этот связанный вопрос; выбранный ответ которого в основном является тем, о чем я прошу здесь.


person i3ensays    schedule 13.01.2009    source источник
comment
Я вижу два голоса, чтобы закрыть --- но я не уверен, что это действительно точная копия запроса на альтернативы. Если меня кто-то убедит, я проголосую за закрытие. (Пожалуйста, оставьте комментарий.)   -  person Norman Ramsey    schedule 13.01.2009
comment
Не дублируется и на самом деле хороший вопрос.   -  person OscarRyz    schedule 13.01.2009
comment
Не дубликат, но Джон Лимджап, кажется, думает иначе. Что я могу сделать?   -  person i3ensays    schedule 13.01.2009
comment
Это был не только Джон Лимджап. За него должны проголосовать 3 человека, он просто стал третьим, кто сделал это.   -  person mmcdole    schedule 13.01.2009
comment
@Simucal - Спасибо за разъяснение. Можно ли проголосовать за его открытие? Было бы полезно, если бы избиратели предоставили ссылку на предполагаемый дубликат.   -  person i3ensays    schedule 13.01.2009
comment
Да, пользователи могут проголосовать за повторное открытие. Для повторного открытия вопроса требуется, чтобы проголосовали 3 пользователя. В настоящее время один пользователь проголосовал за это, поэтому нужно еще два.   -  person mmcdole    schedule 13.01.2009
comment
Вы также должны иметь определенный уровень репутации, чтобы сделать это, этот уровень должен быть в FAQ (3k rep)   -  person mmcdole    schedule 13.01.2009


Ответы (18)


Это полная противоположность, соглашение об именах четко идентифицирует интерфейс.

Например, если у вас есть:

public class Dog : IPet, IMammal
{
    ....

Просто прочитав его, я могу с уверенностью предположить, что IPet и IMammal, вероятно, являются интерфейсами.

.NET CLR допускает наследование одного класса. Итак, если у меня есть базовый класс... я могу наследовать от него только один класс. Давайте изменим интерфейс IPet на базовый класс. Теперь наш пример становится

public class Dog : Pet, IMammal
{
    ....

Я наследую от класса Pet и реализую интерфейс IMmmal.

Если бы мы сделали то, что вы предлагаете, и убрали букву «Я», то получили бы вот это:

public class Dog : Pet, Mammal
{
    ....

От какого класса я наследую? Какой интерфейс я реализую? Это сбивает с толку, верно? (К вашему сведению... вы должны всегда ставить базовый класс первым, поэтому вы можете возразить по этому поводу... но если вы настаиваете на удалении буквы I из префикса имен интерфейсов, я сомневаюсь, что вы также следуете этой практике)

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

person Bart Czernicki    schedule 13.01.2009
comment
Это имеет смысл. Итак, в C# расширения и реализации Java смешаны вместе? - person OscarRyz; 13.01.2009
comment
Я всегда следую базовому классу, который вы упоминаете первым. Тем не менее, я не могу согласиться с вашим соглашением об именовании утверждений, которое легко говорит мне многое о моем объекте. Дело в том, что различие между интерфейсом, абстрактным/конкретным классом, перечислением, стойками и т. д. не имеет для меня смысла на уровне API. - person i3ensays; 13.01.2009
comment
Почему мы не ставим перед абстрактными/конкретными типами префикс A/C, перечисления — E, структуры — S и т. д.? - person i3ensays; 13.01.2009
comment
Я использую среду программирования, которая НАСТОЛЬКО ужасна, что методы, атрибуты и объекты должны начинаться с префикса met, attr и obj соответственно. objEmployee.metUpdate(objOther.attrId). Это очень читабельно и очень ясно, но я просто ненавижу это!!! - person OscarRyz; 13.01.2009
comment
@ Оскар - я не могу понять, саркастичный ты или идиотский. В любом случае, я не думаю, что любой здравомыслящий программист проголосовал бы за такое использование. - person i3ensays; 13.01.2009
comment
не похоже, что это его выбор - person jbu; 16.01.2009
comment
Это лучший ответ, но фактические причины (согласно Кшиштофу Цвалине) заключаются в том, что I используется для historical reasons и (согласно Брэду Абрамсу) что это clear recognition of the influence of COM (and Java) on the .NET Framework, и решение продолжить его было принято потому, что так много первых последователей .NET Framework were already familiar with COM. (См. этот ответ для более подробных цитат. ="существуют ли установленные альтернативы issomething issomethingable для интерфейсов"> stackoverflow.com/questions/222457/) - person Scott Dorman; 30.04.2010
comment
Мне лично нравится, что все интерфейсы имеют префикс «I». Это позволяет мне сразу быстро распознавать интерфейс. - person galford13x; 30.04.2010
comment
Довольно иронично, что java действительно сделала это правильно. Интерфейсы больше не имеют префикса I, но на самом деле это считается ПЛОХОЙ практикой. См. «Эффективная Java» Джошуа Блоха. - person Andriy Drozdyuk; 21.09.2010
comment
Сначала базовый класс — это не просто соглашение. Это требуется компилятором: Base class 'xyz' must come before any interfaces. Это не должно означать, что я против использования I в качестве префикса. Помимо прочего, приятно иметь визуальный индикатор того, насколько интерфейсным является мой код. - person Ryan Lundy; 24.10.2011
comment
Визуальные индикаторы @Kyralessa — это то, что текстовые редакторы / IDE делают довольно хорошо (например, цвет шрифта, значки и т. д.). - person i3ensays; 14.09.2013
comment
К чему это не относится, так это к более фундаментальному вопросу о том, почему вам нужно идентифицировать тип как интерфейс, не больше, чем вам нужно определить, является ли он классом или структурой... или является ли он абстрактным или нет..., или содержит ли он члены-экземпляры или только статические... Я думаю, что да, но я не уверен, какой лучший ответ на вопрос, почему.... - person Charles Bretana; 23.09.2014

Мне также это нравится, потому что я могу прочитать это как «I verb-behavior», как в «ICanSave» или «IDoDoubleEntry» и т. д.

person Charles Bretana    schedule 13.01.2009
comment
Возможно, префикс должен быть «Я». - person mackenir; 13.01.2009
comment
да, можно утверждать, что Am подразумевается. IAmEnumerable, возможно, был бы яснее, хотя и длиннее. - person Charles Bretana; 13.01.2009
comment
Я всегда нахожу названия своих интерфейсов немного похожими на лолкотов. ICanHasЧизбургер - person Iain Galloway; 06.01.2012
comment
Разве это не противоречит соглашениям об именах C#? ICanSave должно быть ISaveble. - person Vapid Linus; 06.05.2017
comment
@ Vapid, я думаю, это может быть очень незначительно, поскольку глагольная фраза, конечно, не является прилагательным, но значение идентично. ISaveble или I[Am]Saveble означает то же самое, что и ICanSave. На самом деле, с моей точки зрения, интерфейсы ближе к реальному смыслу. Интерфейсы — это способы объявить компилятору, что тип (класс или структура) реализует определенный набор поведений, т. е. заставляет компилятор требовать, чтобы тип реализовывал поведение, определенное в интерфейсе. . так что для меня более уместна глагольная фраза, объявляющая, что тип делает что-то. - person Charles Bretana; 06.05.2017
comment
@CharlesBretana Я просто подумал, потому что .NET называет свои интерфейсы IClonable, IDisposable и IComparable, а не ICanClone, ICanDispose или ICanCompare. - person Vapid Linus; 07.05.2017
comment
@Vapid, да, ты прав. Стандартные соглашения об именах говорят, что имена интерфейсов должны быть существительными, словосочетаниями существительных или (в качестве вторичного варианта) прилагательным. В нем не упоминаются глаголы или глагольные фразы. Я просто думаю, что конструкция глагольной фразы более четко выражает концепцию реализации набора поведения. - person Charles Bretana; 07.05.2017

Я думаю, что соглашение об именах IInterface глупо. Это пример венгерской нотации, и я присоединяюсь к школе мысли, которая презирает венгерскую нотацию. Если у вас есть интерфейс только с одной реализацией с таким же именем, рассмотрите возможность того, что это запах кода.

Тем не менее, я все еще использую его, потому что в этом случае IInterface рекомендуется Microsoft, а «стандарт лучше, чем лучше».

person Sean Reilly    schedule 16.01.2009
comment
Я тоже никогда не был поклонником венгерского языка, но недавно я наткнулся на эту старую статью Джоэла, в которой объясняется его происхождение и то, как многие неправильно его поняли - по крайней мере, теперь я могу понять причину этого! joelonsoftware.com/articles/Wrong.html - person Mathias; 30.10.2009

Почему это не функция синтаксической подсветки вместо венгерской нотации? Почему бы IDE просто не выделять курсивом идентификаторы, относящиеся к интерфейсам, если так важно различать классы и интерфейсы. Я ненавижу ставить «» или «m» перед полями, «C» перед классами и т. д. Хуже того, это побуждает программистов писать очень плохие API, такие как:

public class List : IList

вместо более разумного:

public class LinkedList : List
public class ArrayList : List
public class HashList : List

Даже авторы общих классов .NET попали в эту ловушку. Имя класса НИКОГДА не должно быть именем интерфейса, в котором удалена только буква «I». Имя класса всегда должно сообщать пользователю, чем класс отличается от других возможных реализаций интерфейса(ов). Я голосую за отказ от глупого «я» только по этой причине.

Кроме того, когда я использую intellisense, я хочу сгруппировать вещи по функциональным областям, а не по классу или интерфейсу. Я никогда не думаю: «Мне нужен интерфейс, а не класс». Я всегда думаю: «Мне нужно что-то, что делает X».

person Dan    schedule 12.10.2010
comment
Я рад, что я не единственный, кто видит это таким образом. Похоже, я в меньшинстве. Спустя 4 года я все еще поражен тем, как много читателей клянутся, что с его помощью легко идентифицировать интерфейс и полностью упускают суть. - person i3ensays; 14.09.2013
comment
Это действительно хороший момент при проектировании интерфейса с учетом расширяемости, но другой вариант использования абстрагирования интерфейсов (C# и Java) предназначен исключительно для разъединения, позволяющего имитировать зависимости, где никакая другая конкретная реализация интерфейса не использовалась. явно «предназначен для». Так что MyReallySpecificBusinessComponent и IMyReallySpecificBusinessComponent подойдут. Но точно не List. - person StuartLC; 09.12.2015

На самом деле я считаю полезным избегать конфликтов имен, я мог бы, например, создать конкретный класс с именем Fred, который реализует IFred.

person Tim Jarvis    schedule 13.01.2009
comment
Конфликтов имен можно избежать, используя осмысленные/полезные имена. Например. Фред расширяет Person, реализует Living, Breathing и другие возможности. Без дополнительного контекста я не могу сказать наверняка, но если Фред является объектом домена/модели, интерфейс для него, вероятно, излишен. - person i3ensays; 14.09.2013

Мне всегда казалось забавным использовать глаголы для поведенческих интерфейсов. Это отход от соглашения об именовании классов с использованием существительных, но позволяет классу «говорить» о своем поведении.

class Dog: IBark

Это не очень хорошо работает для структурных интерфейсов, таких как интерфейсы WCF, но нам не нужно все время развлекаться.

чтобы ответить на ваш вопрос, подумайте о I как о «орудиях». Итак...

class DogDataService : Dog, IDataService

этот класс обслуживания наследуется от Dog и реализует IDataService

Я все еще не совсем отвечаю на ваш вопрос, но I полезен, потому что вы получаете коллизии имен между пространством имен, классом и интерфейсом.

namespace DataService
interface DataService
class DataService: DataService

так что мы в конечном итоге с

namespace DataServices
interface IDataService
class DataService : IDataService

Я думаю, на самом деле, это соглашение о здравомыслии.

person MarkDav.is    schedule 30.10.2009
comment
+1 - вообще говоря, я думаю, что соглашения об именах указывают на слабость языка разработки (и, вероятно, здесь дело обстоит именно так), но, тем не менее, важно иметь возможность избегать этих коллизий, когда вы хотите использовать внедрение зависимостей и имитировать объекты-сотрудники . На самом деле нет альтернативы соглашению об именах, когда вы создаете интерфейсы для объектов предметной области. - person Jeff Sternal; 30.10.2009
comment
/shrug Я использую его и для сервисов WCF. У меня есть IServeData и ICanMakePayments для двух моих сервисов. - person Kyle; 30.04.2010
comment
@JeffSternal Я думаю, вы могли бы применить к каждому объекту анти-шаблон интерфейса. Вероятно, вам не следует создавать интерфейсы для объектов предметной области; они часто являются ожидаемой частью вашего общедоступного API. - person i3ensays; 17.03.2014

Если вы рассмотрите два «афоризма о передовом опыте»,

четкость превыше всего

и

шум — это плохо

между ними есть конфликт. Вопрос в том, когда ясность становится шумом?

Для меня более шумно (но одинаково четко) писать Person person = new PersonImpl(), чем IPerson person = new Person().

person FatAlbert    schedule 23.12.2011
comment
Или еще лучше: Person p = new TallPerson(); но в моем случае Person вряд ли будет интерфейсом. Вместо этого это базовый тип, который расширяет TallPerson, то есть абстрактный тип. В любом случае интерфейс Person подразумевается его общедоступным API. Я презираю FooImpl() не меньше, чем IFoo. - person i3ensays; 14.09.2013

Либо так, либо добавить "Impl" в реализацию интерфейса (аргх). У меня нет проблем с «Я», это самое простое и понятное имя для интерфейса.

person Otávio Décio    schedule 13.01.2009
comment
Я не согласен с предложением Impl - это был бы напрасный шум, как и префикс I. Реализация должна быть названа с учетом ее реализации. Например, база данных интерфейса может быть реализована с помощью RelationalDatabase и InMemoryDatabase. - person i3ensays; 13.01.2009
comment
Это соглашение, вы не обязаны ему следовать, если оно вам не нравится. - person Otávio Décio; 13.01.2009
comment
Дело не в том, что мне это нравится. Я сомневаюсь в его ценности. Мне нравится придерживаться условностей не только ради следования за стаей. Я хочу понять рациональное. Надеюсь, кто-то сможет сформулировать это рациональное, помимо того, что оно позволяет вам узнать его интерфейс (который IDE делает с красивыми значками). - person i3ensays; 13.01.2009

Конвенция «я» кажется старой условностью, которая не актуальна сегодня. Текущий редактор кода дает много информации об используемом типе, поэтому утверждать, что легче идентифицировать интерфейс, все равно что просить, чтобы пространство имен имело префикс «N», потому что вы хотите быть уверены, что не перепутаете его с конкретный класс (префикс с "C"?).

Конвенция не означает, что это хорошая конвенция. Иногда это просто потому, что люди используют его...

Возьмем, к примеру, генератор документации C#: ему все равно... если ваш интерфейс не имеет префикса "I", вы все равно увидите свой интерфейс в интерфейсной части вашей документации. Вы действительно думаете, что наличие префикса «I» для всех ваших интерфейсов в разделе интерфейса вашей документации является важной информацией и помогает вам лучше идентифицировать интерфейсы?

person Alexandre Mutel    schedule 03.09.2010

Необходимость различать интерфейс и класс на самом деле указывает на недостаток дизайна. В хорошо спроектированном приложении это всегда будет понятно. Подкласс всегда должен быть специализацией, а классы могут специализироваться только на одном предмете и никогда больше.

Класс должен иметь единственную причину существования. Ни в коем случае не следует помещать второстепенные роли в базовый класс. Например.:

public class XmlConfigurationFile : ConfigurationFile, IDisposable
{
}

public class YamlConfigurationFile : ConfigurationFile, IDisposable
{
}

Первый — это файл конфигурации, специализированный на Xml, второй — на Yaml. Они тоже одноразовые, но это не так важно. Вы не создали эти два класса из-за разных процессов утилизации.

Сравните это с:

public class XmlConfigurationFile : IDisposable, ConfigurationFile
{
}

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

Проблема начинается, когда вы создаете классы, у которых есть несколько причин существования:

public class MyConfigurationFile : XmlConfigurationFile, YamlConfigurationFile
{
}

Даже если XmlConfigurationFile и YamlConfigurationFile были бы интерфейсами, это все равно указывает на плохой дизайн. Как ваш файл конфигурации может быть Xml и Yaml одновременно?

Если вы прочитаете приведенные примеры (здесь и в других местах), люди всегда изо всех сил пытаются найти хороший пример того, когда I-префикс имеет значение. Один из ответов здесь:

public class Dog : Pet, Mammal
{
}

Вот так этот класс будет выглядеть в приложении про домашних животных. Основная цель собаки — быть специализированным домашним животным, которое может делать вещи, связанные с домашним животным, а не млекопитающим.

public class Dog : Mammal, Pet
{
}

Вот так этот же класс будет выглядеть в приложении о классификации животных. Приятно знать, что собака — домашнее животное, но ее основная цель — быть специализированным млекопитающим, которое может делать вещи, связанные с млекопитающими.

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

Как только вы начнете писать небольшие, специализированные, одноцелевые классы, необходимость знать, реализует ли он или расширяет, автоматически исчезнет.

person Jeroen    schedule 05.08.2016
comment
Это должен быть утвержденный ответ. Хорошо написано и информативно. Спасибо. - person Sukima; 13.11.2020

Это делает его легко идентифицируемым как интерфейс.

person scottm    schedule 13.01.2009
comment
Я не вижу прямой ценности в разграничении интерфейсов и реализаций. Дальнейшая разработка может помочь. - person i3ensays; 13.01.2009
comment
Для меня, по крайней мере, реализация означает класс, который должен быть определен в соответствии с логической семантикой сущности/объекта, тогда как интерфейс означает поведение или контракт, который должен быть организован в соответствии с логическими группами связанных поведений. - person Charles Bretana; 13.01.2009

Соглашения об именовании предлагают то преимущество, что сообщают вам что-то об объекте до того, как вы его используете. Соглашения об именах широко использовались в течение многих лет, начиная с того, что Фортран настаивал на том, чтобы целые значения были ограничены (если я правильно помню) именами переменных, такими как «i» и «j».

Венгерская нотация вывела соглашения об именах на совершенно новый уродливый уровень, который описывал тип переменной, независимо от того, была ли она указателем и т. д. У многих из нас, кто столкнулся с большим количеством кода с венгерской нотацией, начались нервные подергивания и словесные заикания.

Префикс I к именам интерфейсов является относительно малозатратным и безвредным способом идентификации этого объекта.

person Kluge    schedule 13.01.2009
comment
Как идентификация типа как интерфейса приносит пользу API? (Я понимаю разницу между интерфейсами и классами). - person i3ensays; 13.01.2009

TL;DR – извлечение interface IFoo из class Foo часто используется при разделении SOLID, особенно для целей модульного тестирования

Для меня двойное соглашение класса Foo, реализующего интерфейс IFoo (особенно если оба они находятся в одной сборке), передает конкретное намерение:

  • Связывание зависимости с Foo всегда должно быть косвенным, через соответствующий интерфейс IFoo (и, вероятно, будет внедрено через контейнер IoC).
  • Первоначальный дизайн IFoo представляет собой проприетарный интерфейс, не допускающий повторного использования, специально для того, чтобы позволить классам, зависящим от Foo, имитировать эту зависимость во время модульного тестирования.
  • Помимо вышеизложенного, читателю не нужно делать каких-либо дополнительных выводов о дизайне интерфейса IFoo.
  • И наоборот, если на более позднем этапе потребуется несколько конкретных классов реализации IFoo, этот надлежащий дизайн сегрегации интерфейса необходимо будет модифицировать в иерархии.

Обоснование

Чтобы иметь возможность смоделировать или заглушить класс, широко распространенной передовой практикой в ​​модульном тестировании является разделение зависимостей между классами только через интерфейсы. Это разделение интерфейса также будет выполнено для классов, которые в противном случае никогда не требовал полиморфизма (т.е. существовала бы только одна такая реализация, если бы не необходимость модульного тестирования).

Как следствие, рефакторинг и повторное использование этих интерфейсов (например, Принцип разделения интерфейсов SOLID) не часто применяется к таким «фиктивным» интерфейсам — часто существует корреляция 1: 1 между общедоступными методами, свойствами и событиями «фиктивного» класса (Foo) и его разъединенного интерфейса IFoo (аналогично COM-эре автоматические интерфейсы в VB).

Такие инструменты, как VS и Resharper, могут упростить извлечение таких общедоступных символов из class в отдельный интерфейс тривиально, как запоздалую мысль.

Далее, если учесть, что фреймворки Mocking, такие как Moq, позволяют определять реализации интерфейса на -fly, нам не нужно тратить усилия на то, чтобы назвать конкретный класс двойной реализации теста.

person StuartLC    schedule 14.11.2015

Это просто соглашение об именах, чтобы все знали, является ли это интерфейсом или чем-то еще, это не является обязательным ни для компилятора, ни для IDE, но все интерфейсы, которые я видел за всю свою жизнь, начинаются с буквы я

person Hannoun Yassir    schedule 30.04.2010

Кажется, я придерживаюсь традиционного соглашения из венгерской нотации. В Руководстве по именованию интерфейсов говорится: "Префикс интерфейса имена с буквой I, чтобы указать, что тип является интерфейсом». В Руководстве по проектированию фреймворка также говорится: "Префиксировать имена интерфейсов буквой I, чтобы указать, что тип является интерфейсом».

Это просто соглашение о кодировании, поэтому трудно определить, хорошо это или плохо. Важные вещи - последовательность.

person Namo    schedule 29.11.2013

Во-первых, я считаю, что префикс I, затем описание неверен, потому что это означает, что реализации могут иметь более короткое имя. IList(intf) -> Список. Это анти-шаблон, поскольку мы все знаем, что при создании следует использовать intf и, возможно, только конкретные типы. Не обижайте меня, это обобщение, но предпосылка используется редко. Имя реализации должно описывать, как он реализует intf или что он делает. Подумайте о intf List, LinkedList, который реализует List, используя связанный список. Кого волнует, что он длиннее, поскольку мы должны использовать List большую часть времени. Если у нас есть класс, реализующий множество intf, нам, вероятно, не следует включать все intf, поскольку они скрывают реальную цель класса. В случае, если что-то удалено без intf имеет смысл. Например, люди называют меня по имени, а не по имени Человек, брат, сестра, разработчик и т. д., используя мое имя — это лучшее наиболее описательное имя. Я полагаю, что если класс представляет собой простой intf, то назовите его Intf по умолчанию, что делает его ious, это реализация Intf по умолчанию. Имена классов в итоге должны быть удобочитаемыми и почти короткой фразой, описывающей их назначение. Коды префиксов и т. д. не очень хороши, поскольку мы общаемся с помощью слов, а не кодов. Компьютерам все равно, как называются классы, так что остается только называть вещи так, чтобы имена помогали нам и нашим коллегам.

person mP.    schedule 30.04.2010

Скорее всего, это делается для того, чтобы его было легко идентифицировать в intellisense, поскольку все интерфейсы будут слипаться. Подобно тому, как я добавляю префикс ко всем своим элементам управления пользовательского интерфейса с помощью btn, tb, lb. Когда intellisense срабатывает, все объединяется в одну простую группу.

person Kwan Cheng    schedule 13.01.2009
comment
Я считаю, что IDE может слипаться без использования соглашений об именах. - person i3ensays; 13.01.2009

Со всеми аргументами о соглашениях об именах и присвоении правильных имен переменным и методам, которые на самом деле описывают то, что они делают... почему бы просто не назвать свои интерфейсы (например, PetInterface, PlayerInterface и т. д.) и покончить с префиксом "I" во всех вместе. Итак, что вы должны ввести дополнительные 9 букв, по крайней мере, "I" удалено, и мы знаем, что это не класс, потому что он говорит "Интерфейс".

person Darren    schedule 27.10.2014
comment
Это ужасная идея. Почему бы не назвать ваши классы DogClass? Если бы кто-то сделал это в моей кодовой базе, я бы очень расстроился. Есть стандарт; используй это. - person BradleyDotNET; 27.10.2014