Конвенція іменування C # для переліку та відповідності властивості


93

Я часто виявляю себе реалізовуючим клас, що підтримує якусь власну властивість статусу як перерахування: у мене є перелік статусу та ОДНА властивість статусу типу Status. Як мені вирішити цей конфлікт назв?

public class Car
{
  public enum Status
  {
    Off,
    Starting,
    Moving
  };

  Status status = Status.Off;

  public Status Status // <===== Won't compile =====
  {
    get { return status; }
    set { status = value; DoSomething(); }
  }
}

Якби перелік Status був загальним для різних типів, я б поставив його поза класом, і проблема була б вирішена. Але Статус застосовується лише до автомобіля, тому не має сенсу оголошувати перелік поза класом.

Яку конвенцію іменування ви використовуєте в цьому випадку?

NB: Це питання частково обговорювалось у коментарях до відповіді на це питання . Оскільки це не було головним питанням, воно не мало великої видимості.

РЕДАГУВАТИ: Філіп Екберг пропонує відмінне рішення ІМО для конкретного випадку "Статусу". Тим НЕ менше , я б цікаво читати про рішення , де ім'я перерахувань / власність відрізняється, як і в Майкла Prewecki в відповідь .

EDIT2 (травень 2010 р.): Моє улюблене рішення - це плюралізація імені типу перечислення, як запропонував Кріс С. Відповідно до керівних принципів MS, це слід використовувати лише для перелічень прапорів. Але мені це все більше подобається. Зараз я використовую його і для регулярних зарахувань.


1
Я не думаю, що для цього існує багато хороших рішень, якщо ви хочете, щоб перелік вклався всередину вашого класу. Я насправді вважаю за краще, щоб перерахування було відокремленим, тоді це не представляє проблеми, але я бачу вашу філософську думку щодо бажання вкласти його.
Крейг Ширер,

Відповіді:


32

Я додаю до обговорення свій 1 євро, але це, мабуть, не додає нічого нового.

Очевидним рішенням є переміщення Status із вкладеного Enum. Більшість перечислень .NET (за винятком, можливо, деяких у просторі імен Windows.Forms) не вкладені, і це дратує використання для розробника, який споживає ваш API, з необхідністю вводити префікс до імені класу.

Одне, про що не згадувалось, - це те, що перелічення прапорів відповідно до керівних принципів MSDN мають бути іменниками з множиною, які ви, напевно, вже знаєте (Status - це просте перерахування, тому слід використовувати іменники однини).

State (enum, що називається States) - це вокатив, "Status" - номінатив іменника, який англійська мова, як і більшість нашої мови, вбирає з латини. Вокатив - це те, що ви називаєте іменником за його станом, а номінатив - предмет дієслова.

Отже, іншими словами, коли автомобіль рухається , це дієслово - рух - це його статус. Але машина не згасає, а її двигун. Він також не запускається, а двигун (ви, мабуть, вибрали тут приклад, тому це може бути неактуальним).

public class Car
{
  VehicleState _vehicleState= VehicleState.Stationary;

  public VehicleState VehicleState 
  {
    get { return _vehicleState; }
    set { _vehicleState = value; DoSomething(); }
  }
}

public enum VehicleState
{
    Stationary, Idle, Moving
}

Держава - це такий узагальнений іменник, чи не краще було б описати, до якого стану він має на увазі? Як я робив вище

Приклад типу також, на мій погляд, стосується не типу читача, а його бази даних. Я б віддав перевагу, якби ви описували продукт бази даних читача, який не обов'язково відповідає типу зчитувача (наприклад, тип зчитувача може бути лише пересиланням, кешованим тощо). Так

reader.Database = Databases.Oracle;

Насправді цього ніколи не відбувається, оскільки вони реалізовані як драйвери та ланцюжок успадкування замість використання перерахувань, тому рядок вище не виглядає природним.


24
Я розумію, що прапори мають бути множинні, а не прості переліки.
Serge Wautier

8
щодо переміщення переліків з класу, я ще не зрозумів, чому CarState зручніший за Car.State. Однак я не розумію позитивної сторони виведення переліку з класу, коли цей перелік описує поведінку лише цього класу.
Serge Wautier

Я повинен був писати іменні фрази, як FileOptions, а не просто іменники, я оновив відповідь. Я припускаю, що classname.Enum - це лише перевага - я не можу знайти жодних прикладів в рамках, які, в підсумку, копіюю.
Chris S

Незважаючи на те, що MS стверджує, що для прапорів слід зберігати множину, з часом мені все більше до вподоби ці рішення. Зараз я використовую його також для переліків. Тому я передумав і прийняв вашу відповідь замість відповіді Філіпа.
Серж Вотьє,

1
Я знаю, що я запізнився тут на 1 1/2 року, але public class EngineStateмав би бути public enum EngineStateв цьому прикладі, так?
Девід Мердок

36

Визначення "вимкнено", "починається" та "рухається" - це те, що я б назвав "державою". І коли ви натякаєте, що використовуєте "штат", це ваш "статус". Так!

public class Car
{
  public enum State
  {
    Off,
    Starting,
    Moving
  };

  State state = State.Off;

  public State Status
  {
    get { return state ; }
    set { state= value; DoSomething(); }
  }
}

Якщо ми візьмемо інший приклад із зазначеного, де ви хочете використовувати слово "Тип", наприклад, у цьому випадку:

public class DataReader
{
    public enum Type
    {
        Sql,
        Oracle,
        OleDb
    }

    public Type Type { get; set; } // <===== Won't compile =====

}

Вам справді потрібно побачити, що між переліченнями та переліками існує різниця, так? Але коли створюєте фреймворк або розмовляєте про архітектуру, вам потрібно зосередитись на подібності, добре давайте їх знайти:

Коли щось встановлено як стан, це визначається як статус "речей"

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

Що ви хочете отримати в другому прикладі, дещо таке:

myDataReader.Type = DataReader.Database.OleDb

Ви можете подумати, що це суперечить тому, про що я проповідував іншим, що вам потрібно дотримуватися стандартів. Але, ви дотримуєтесь стандарту! Справа Sql є також конкретним випадком, тому потребує дещо конкретного рішення.

Однак перелік може бути повторно використаний у вашому System.Dataпросторі, і саме в цьому полягають шаблони.

Інший випадок, який слід поглянути на "Тип" - це "Тварина", де Тип визначає Види.

public class Animal
    {
        public enum Type
        {
            Mammal,
            Reptile,
            JonSkeet
        }

        public Type Species{ get; set; }

    }

Це слідує шаблону, вам не потрібно конкретно "знати" Об'єкт для цього, і ви не вказуєте "AnimalType" або "DataReaderType", ви можете повторно використовувати перелічення у вибраному просторі імен.


1
Я вважаю, що назва "Статус" була лише прикладом. А як щодо інших ситуацій, коли ви не можете покладатися на статус / стан? Наприклад, перелік типів ...
Ден К.

Не могли б ви надати приклад сценарію для цього? погано намагаюся розширити свою відповідь відповідно до цього :)
Філіп Екберг

2
@Filip: зразок Animal Type вказує саме на те, що я мав на увазі в першому коментарі, тобто це майже "переформулювання" переліку. Думаю, використання синонімів для переліку та назви властивості робить код дещо заплутаним.
Dan C.

1
Я також думаю, що "вид" - це просто переформулювання типу (у даному випадку для тварин).
LegendLength

2
Просто перейменування не завжди настільки чисте - придумайте клас для ігрової карти, наприклад, з enum Suit та властивістю Suit - перейменувати на що саме? Невмілий в будь-якому випадку.
annakata

9

Я думаю, що справжня проблема тут полягає в тому, що статус переліку перебуває у складі вашого класу, що Car.Statusє неоднозначним як для властивості, так Statusі для перелікуStatus

А ще краще, поставте свій перелік поза класом:

public enum Status
{
    Off,
    Starting,
    Moving
}

public class Car
{
    public Status Status
    { ... }
}

ОНОВЛЕННЯ

Через коментарі нижче я пояснитиму свій дизайн вище.

Я той, хто не вважає, що перелічення чи класи чи будь-який інший об'єкт повинен знаходитись всередині іншого класу, якщо тільки він не буде повністю приватним у цьому класі. Візьмемо наведений вище приклад, наприклад:

public class Car
{
    public enum Status
    {...}
    ...
    public Status CarStatus { get; set;}
}

У той час як деякі коментатори стверджують , що статус не мають ніякого значення поза рамками класу Car, той факт , що ви встановлюєте суспільне властивість означає , що Є інші частини програми , які будуть використовувати це перерахування:

public Car myCar = new Car();
myCar.CarStatus = Car.Status.Off;

І це для мене кодовий запах. Якщо я буду дивитися на цей статус зовнішньої частини Car, я міг би також визначити його межами , а також.

Таким чином, я, мабуть, просто перейменую його як:

public enum CarStatus
{...}

public class Car
{
    ...
    public CarStatus Status { get; set; }
}

Однак, якщо цей перелік буде використовуватися всередині класу автомобілів і тільки в ньому, тоді я добре оголошую там перелік.


Це зробило б статус глобальним, можливо, ви захочете мати його просто в певній області. "Статус" для інших типів, таких як "Людина", може не мати "Запуск". Але слід дотримуватися шаблону.
Філіп Екберг

Ні, він на місці. Перерахування в 99% випадків є тим самим словом, яке ви хочете використовувати для власності. Enum - це лише названий прапор, тому він не завдає шкоди життю поза межами (на відміну від класів, що містять логіку)
дивовижний

Джон, це саме моя думка: перелік статусів має значення лише щодо автомобіля. Абсолютно різні типи об'єктів матимуть абсолютно різні статуси
Серж Вотьє,

вони будуть знаходитися в різних просторах імен, тому це не буде мати значення
Кріс С

Пояснення, що бажаючи поглянути на це за межами автомобіля, має сенс. Але в моєму випадку у мене є два класи, ORі CR. Обидва мають свій власний набір станів, тому неможливо визначити їх поза власним обсягом.
deed02392

4

Я знаю, що моя пропозиція суперечить конвенціям .NET Naming, але я особисто додаю префікси enum до "E", а прапорці enum до "F" (подібно до того, як ми додаємо інтерфейси до "I"). Я справді не розумію, чому це не конвенція. Enums / Flags - це особливий випадок, такий як Інтерфейси, які ніколи не змінять свій тип. Це не тільки дає зрозуміти, що це таке, це дуже легко ввести в intellisense, оскільки префікс фільтрує більшість інших типів / змінних / тощо, і у вас не буде цих зіткнень імен.

І це також вирішило б іншу проблему, коли для прикладів у WPF вони використовують статичні класи, такі як перерахування (наприклад, FontWeights), які мають заздалегідь визначені екземпляри типів, але ви б не знали, якщо не шукаєте його. Якщо вони просто поставили їм префікс "E", все, що вам потрібно зробити, це набрати символ, щоб знайти ці спеціальні статичні класи.


4

Ненависники угорської нотації та її варіантів будуть прокляті. Я використовую домовленість суфіксації перечислень з - чекай на це - Enum. Отже, у мене ніколи не виникає проблеми, яку ви описуєте, витрачаючи час на роздуми про те, як їх назвати, а код для читання та самоопису для завантаження.

public class Car
{
  public enum StatusEnum
  {
    Off,
    Starting,
    Moving
  };

  public StatusEnum Status { get; set; }

}

9
Зверніть увагу, однак, що в конвенції Microsoft щодо перерахування імен зазначено: X НЕ використовуйте суфікс "Enum" в назвах типів
DavidRR

2
Оскільки конвенції Microsoft, як було доведено, витримують випробування часом.
nathanchere

2

Я б змінив назву властивості на щось на зразок "CurrentStatus". Швидко і просто :)


1

Я пропоную додати назву "Option" до імені типу (або Flag, якщо воно містить бітові прапори), тобто тип - Car.StatusOption, а властивість - Car.Status.

Порівняно з плюралізацією, це дозволяє уникнути зіткнень імен при створенні колекцій типу enum, де зазвичай потрібно плюралізувати властивість колекції , а не тип enum .


0

Зазвичай я додаю префікси до переліків, наприклад CarStatus. Думаю, все залежить від команди, з якою ви працюєте (якщо у них є якісь правила / процеси для подібного роду) та використання об’єктів. Лише мої 2 центи (:


1
Це насправді вбило б конвенцію про іменування, що має MyObjectName перед Status.
Філіп Екберг

простору імен з класу в будь-якому випадку має бути достатньо, щоб розібратися з цим
annakata
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.