Konwencja nazewnictwa C # dla wyliczenia i pasującej właściwości

93

Często zdarza mi się implementować klasę, która utrzymuje jakąś własną właściwość statusu jako wyliczenie: mam wyliczenie Status i JEDEN Właściwość Status typu Status. Jak mam rozwiązać ten konflikt nazw?

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(); }
  }
}

Gdyby wyliczenie Status było wspólne dla różnych typów, umieściłbym je poza klasą i problem zostałby rozwiązany. Ale Status dotyczy tylko samochodu, dlatego nie ma sensu deklarowanie wyliczenia poza klasą.

Jakiej konwencji nazewnictwa używasz w tym przypadku?

Uwaga: to pytanie było częściowo omawiane w komentarzach do odpowiedzi na to pytanie . Ponieważ nie było to główne pytanie, nie było zbyt dobrze widoczne.

EDYCJA: Filip Ekberg sugeruje doskonałe obejście IMO dla konkretnego przypadku „Status”. Byłbym jednak interesujący, gdyby przeczytał o rozwiązaniach, w których nazwa wyliczenia / właściwości jest inna, jak w odpowiedź .

EDIT2 (maj 2010): Moim ulubionym rozwiązaniem jest dodanie liczby mnogiej nazwy typu wyliczenia, zgodnie z sugestią Chrisa S. Zgodnie z wytycznymi MS, powinno to być używane tylko dla wyliczeń flag. Ale coraz bardziej to lubię. Teraz używam go również do zwykłych wyliczeń.

Serge Wautier
źródło
1
Nie sądzę, aby było wiele dobrych rozwiązań, jeśli chcesz mieć zagnieżdżone wyliczenie w swojej klasie. Właściwie wolę, aby wyliczenie było oddzielne, ponieważ nie stanowi to problemu, ale widzę twój punkt widzenia filozoficzny dotyczący chęci zagnieżdżenia go.
Craig Shearer

Odpowiedzi:

32

Dodam do dyskusji moje 1 euro, ale prawdopodobnie nie dodam niczego nowego.

Oczywistym rozwiązaniem jest usunięcie statusu zagnieżdżonego Enum. Większość wyliczeń .NET (z wyjątkiem być może niektórych w przestrzeni nazw Windows.Forms) nie jest zagnieżdżonych, co sprawia, że ​​używanie przez programistę używającego interfejsu API jest denerwujące, ponieważ musi poprzedzać nazwę klasy.

Jedną rzeczą, o której nie wspomniano, jest to, że wyliczenia flag zgodnie z wytycznymi MSDN powinny być rzeczownikami w liczbie mnogiej wyliczenia liczbie które prawdopodobnie już znasz (Status jest prostym wyliczeniem, więc należy używać rzeczowników w liczbie pojedynczej).

Stan (wyliczenie nazywane Stany) jest wołaczem, „Status” jest mianownikiem rzeczownika, który język angielski, podobnie jak większość naszego języka, został wchłonięty z łaciny. Vocative to to, co nazywasz rzeczownikiem ze względu na jego stan, a mianownik jest podmiotem czasownika.

Innymi słowy, kiedy samochód się porusza , to jest czasownik - ruch to jego status. Ale samochód nie gaśnie, ale jego silnik. Ani się nie uruchamia, ale silnik nie (prawdopodobnie wybrałeś tutaj przykład, więc może to nie mieć znaczenia).

public class Car
{
  VehicleState _vehicleState= VehicleState.Stationary;

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

public enum VehicleState
{
    Stationary, Idle, Moving
}

Stan jest tak uogólnionym rzeczownikiem, czy nie lepiej byłoby opisać, do jakiego stanu się odnosi? Tak jak powyżej

Przykład typu również w moim widoku nie odnosi się do typu czytnika, ale do jego bazy danych. Wolałbym, żebyś opisywał produkt bazy danych czytelnika, który niekoniecznie jest odpowiedni dla typu czytnika (np. Typ czytnika może być tylko przekazywany, buforowany i tak dalej). Więc

reader.Database = Databases.Oracle;

W rzeczywistości tak się nigdy nie dzieje, ponieważ są one zaimplementowane jako sterowniki i łańcuch dziedziczenia zamiast używać wyliczeń, dlatego powyższa linia nie wygląda naturalnie.

Chris S.
źródło
24
Rozumiem, że flagi powinny być liczone w liczbie mnogiej, a nie proste wyliczenia.
Serge Wautier
8
jeśli chodzi o przenoszenie wyliczeń z zajęć, nie rozumiem jeszcze, dlaczego CarState jest wygodniejsze niż Car.State. Jednak nie rozumiem pozytywnej strony uzyskiwania wyliczenia z klasy, gdy to wyliczenie opisuje tylko zachowanie tej klasy.
Serge Wautier
Powinienem był napisać frazy rzeczownikowe, takie jak FileOptions, nie tylko rzeczowniki, zaktualizowałem odpowiedź. Przypuszczam, że nazwa klasy.Enum to tylko preferencja - nie mogę znaleźć żadnych przykładów we frameworku, które ostatecznie skopiuję.
Chris S
Chociaż MS mówi, że dla flag powinno się używać liczby mnogiej, z biegiem czasu te rozwiązania polubiłem coraz bardziej. Teraz używam go również do wyliczeń. Dlatego zmieniłem zdanie i zaakceptowałem twoją odpowiedź zamiast Filipa.
Serge Wautier
1
Wiem, że spóźniłem się tu o 1,5 roku, ale public class EngineStatepowinienem być public enum EngineStatew tym przykładzie, prawda?
David Murdoch
36

Definicje „Off”, „Start” i „Moving” to coś, co nazwałbym „Stanem”. A kiedy sugerujesz, że używasz „Stanu”, jest to Twój „Status”. Więc!

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

  State state = State.Off;

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

Jeśli weźmiemy inny przykład z podanego, w którym chciałbyś użyć słowa „Typ”, w tym przypadku:

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

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

}

Naprawdę musisz zobaczyć, że istnieje różnica między wyliczeniami a wyliczeniami, prawda? Ale tworząc framework lub rozmawiając o architekturze, musisz skupić się na podobieństwach, ok, znajdźmy je:

Kiedy coś jest ustawione na stan, jest to definiowane jako stan „rzeczy”

Przykład: stan samochodu to Running State, Stopped i tak dalej.

To, co chcesz osiągnąć w drugim przykładzie, jest mniej więcej takie:

myDataReader.Type = DataReader.Database.OleDb

Możesz pomyśleć, że to mówi przeciwko temu, o czym głosiłem innym, że musisz przestrzegać standardu. Ale postępujesz zgodnie ze standardem! Przypadek Sql jest również szczególnym przypadkiem i dlatego wymaga nieco konkretnego rozwiązania.

Jednak wyliczenie będzie możliwe do ponownego użycia w Twoim System.Data przestrzeni i o to właśnie chodzi we wzorcach.

Innym przypadkiem, któremu należy przyjrzeć się z „Typem”, jest „Zwierzę”, gdzie Typ określa gatunek.

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

        public Type Species{ get; set; }

    }

Jest to zgodne z wzorcem, nie musisz specjalnie „znać” obiektu w tym celu i nie określasz „AnimalType” ani „DataReaderType”, możesz ponownie użyć wyliczeń w wybranej przestrzeni nazw.

Filip Ekberg
źródło
1
Myślę, że nazwa „Status” była tylko przykładem. A co z innymi sytuacjami, kiedy nie możesz polegać na statusie / stanie? Np. Wyliczenie typu ...
Dan C.
2
@Filip: próbka typu zwierzęcia dokładnie wskazuje, co miałem na myśli w pierwszym komentarzu, tj. Jest to prawie „przeformułowanie” wyliczenia. Myślę, że używanie synonimów wyliczenia i nazwy właściwości sprawia, że ​​kod jest nieco zagmatwany.
Dan C.
1
Myślę też, że „gatunek” to tylko przeformułowanie typu (w tym przypadku dla zwierząt).
LegendLength,
2
Zwykła zmiana nazwy nie zawsze jest taka czysta - pomyśl o klasie dla karty do gry, na przykład z kostiumem enum i kostiumem właściwości - zmień nazwę na dokładnie? Tak czy inaczej niezdarny.
annakata
1
takie podejście prowadzi do nieporozumień i pomieszania kodu
Boogier
9

Myślę, że prawdziwy problem polega na tym, że stan wyliczenia jest zamknięty w klasie, co Car.Statusjest niejednoznaczne zarówno dla właściwości, jak Statusi wyliczeniaStatus

Jeszcze lepiej, umieść wyliczenie poza klasą:

public enum Status
{
    Off,
    Starting,
    Moving
}

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

AKTUALIZACJA

Ze względu na poniższe komentarze wyjaśnię powyżej mój projekt.

Jestem osobą, która nie wierzy, że wyliczenia, klasy lub jakikolwiek inny obiekt powinien znajdować się w innej klasie, chyba że będzie to całkowicie prywatne w tej klasie. Weźmy na przykład powyższy przykład:

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

Podczas gdy niektórzy komentatorzy twierdzą, że Status nie ma żadnego znaczenia poza zakresem klasy Car, fakt, że ustawiasz właściwość publiczną, oznacza, że ​​istnieją inne części programu, które będą używać tego wyliczenia:

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

A to dla mnie zapach kodu. Jeśli mam patrzeć na tego statusu zewnątrz z Car, równie dobrze mogę zdefiniować go na zewnątrz , jak również.

W związku z tym prawdopodobnie zmienię jego nazwę na:

public enum CarStatus
{...}

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

Jeśli jednak to wyliczenie będzie używane w obrębie klasy samochodu i tylko w jej obrębie , mogę zadeklarować tam wyliczenie.

Jon Limjap
źródło
To sprawiłoby, że Status byłby globalny, możesz chcieć mieć go tylko w określonym obszarze. „Stan” dla innych typów, takich jak „Człowiek”, może nie mieć opcji „Uruchamianie”. Ale powinieneś podążać za wzorem.
Filip Ekberg
Nie, on jest na miejscu. Wyliczenie jest w 99% przypadków tym samym słowem, którego chcesz użyć dla właściwości. Enum jest tylko flaga nazwana tak robi trochę szkód w żywej zewnątrz (w przeciwieństwie do klas, które zawierają logikę)
Quibblesome
Jon, właśnie o to mi chodzi: wyliczenie Statusu ma znaczenie tylko w odniesieniu do samochodu. Zupełnie różne typy obiektów będą miały zupełnie inne statusy
Serge Wautier
będą one jednak znajdować się w różnych przestrzeniach nazw, więc to nie ma znaczenia
Chris S
Wyjaśnienie, że chęć spojrzenia na to poza samochodem ma sens. Ale w moim przypadku mam dwie klasy ORi CR. Oba mają własny zestaw stanów, więc nie można ich definiować poza własnym zakresem.
deed02392
4

Wiem, że moja sugestia jest sprzeczna z konwencjami nazewnictwa .NET, ale osobiście poprzedzam wyliczenia literą „E”, a flagi wyliczenia literą „F” (podobnie jak w przypadku interfejsów poprzedzamy literę „I”). Naprawdę nie rozumiem, dlaczego to nie jest konwencja. Wyliczenia / flagi to szczególny przypadek, taki jak interfejsy, które nigdy nie zmienią swojego typu. Nie tylko wyjaśnia, co to jest, ale jest bardzo łatwe do wpisania w trybie Intellisense, ponieważ przedrostek będzie filtrował większość innych typów / zmiennych / itp. I nie będzie takich konfliktów nazw.

Rozwiązałoby to również inny problem, w którym w przykładach w WPF używają klas statycznych, takich jak wyliczenia (np. FontWeights), które mają wstępnie zdefiniowane wystąpienia typów, ale nie wiesz, czy ich nie szukasz. Gdyby po prostu dodali do nich przedrostek „E”, wszystko, co musiałbyś zrobić, to wpisać znak, aby znaleźć te specjalne klasy statyczne.


źródło
4

Niech będą przeklęci hejterzy notacji węgierskiej i jej odmian. Używam konwencji dodawania wyliczeń z sufiksem - poczekaj na to - Enum. W rezultacie nigdy nie mam problemu, który opisujesz, tracę czas na martwienie się, jak je nazwać, a kod jest czytelny i samoopisowy do uruchomienia.

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

  public StatusEnum Status { get; set; }

}
nathanchere
źródło
9
Należy jednak pamiętać, że zgodnie z konwencją firmy Microsoft dotyczącą nazewnictwa wyliczeń : X NIE używaj sufiksu „Wyliczenie” w nazwach typów wyliczeniowych.
DavidRR
2
Ponieważ konwencje Microsoftu wytrzymały próbę czasu.
nathanchere
2

Zmieniłbym nazwę właściwości na coś w rodzaju „CurrentStatus”. Szybko i łatwo :)

TWith2Sugars
źródło
1

Proponuję dodać „Option” do nazwy typu (lub Flag, jeśli zawiera flagi bitowe), tj. Typ to Car.StatusOption, a właściwość to Car.Status.

W porównaniu do liczby mnogiej pozwala to uniknąć kolizji nazw podczas tworzenia kolekcji typu wyliczeniowego, w przypadku których normalnie chcesz utworzyć liczbę mnogą właściwości kolekcji , a nie typu wyliczenia .

Kristian Wedberg
źródło
0

Zwykle poprzedzam wyliczenia, np. CarStatus. Przypuszczam, że wszystko zależy od zespołu, z którym pracujesz (jeśli mają jakieś zasady / procesy na tego typu rzeczy) i wykorzystania obiektów. Tylko moje 2 centy (:

Kieron
źródło
1
To faktycznie zabiłoby konwencję nazewnictwa, mając MyObjectName przed Status.
Filip Ekberg
Przestrzenie nazw z klasy i tak powinny wystarczyć, aby sobie z tym poradzić
annakata