Convenção de nomenclatura C # para enum e propriedade correspondente

93

Muitas vezes me vejo implementando uma classe que mantém algum tipo de propriedade de status própria como um enum: Eu tenho um enum de Status e UMA propriedade de Status do tipo Status. Como devo resolver esse conflito de nome?

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

Se o enum Status fosse comum a diferentes tipos, eu o colocaria fora da classe e o problema seria resolvido. Mas Status se aplica a Car apenas, portanto, não faz sentido declarar o enum fora da classe.

Que convenção de nomenclatura você usa neste caso?

NB: Esta questão foi parcialmente debatida nos comentários de uma resposta a esta questão . Como não era a questão principal , não teve muita visibilidade.

EDITAR: Filip Ekberg sugere uma excelente solução alternativa da IMO para o caso específico de 'Status'. Ainda assim, seria interessante ler sobre soluções em que o nome do enum / propriedade é diferente, como na resposta de Michael Prewecki .

EDIT2 (maio de 2010): Minha solução favorita é pluralizar o nome do tipo enum, conforme sugerido por Chris S. De acordo com as diretrizes do MS, isso deve ser usado apenas para enums de sinalizador. Mas passei a gostar cada vez mais. Agora também o uso para enums regulares.

Serge Wautier
fonte
1
Não acho que haja muitas soluções boas para isso se você quiser ter o enum aninhado dentro de sua classe. Na verdade, eu prefiro ter o enum separado, então isso não representa um problema, mas posso entender seu ponto filosoficamente sobre querer aninhá-lo.
Craig Shearer

Respostas:

32

Vou adicionar meu 1 euro à discussão, mas provavelmente não está adicionando nada de novo.

A solução óbvia é mover o Status de um Enum aninhado. A maioria dos enums .NET (exceto possivelmente alguns no namespace Windows.Forms) não estão aninhados e isso torna irritante o uso para o desenvolvedor que consome sua API, tendo que prefixar o nome da classe.

Uma coisa que não foi mencionada é que enums de sinalizadores de acordo com as diretrizes do MSDN devem ser substantivos pluralizados que você provavelmente já conhece (Status é um enum simples, portanto, substantivos singulares devem ser usados).

Estado (enum chamado Estados) é o vocativo, "Status" é o nominativo de um substantivo que o inglês, como a maioria de nossa língua, absorveu do latim. Vocativo é o que você nomeia um substantivo por sua condição e nominativo é o sujeito do verbo.

Em outras palavras, quando o carro está se movendo , esse é o verbo - movendo é o seu status. Mas o carro não dispara, o motor sim. O motor também não liga (você provavelmente escolheu um exemplo aqui, então isso pode ser irrelevante).

public class Car
{
  VehicleState _vehicleState= VehicleState.Stationary;

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

public enum VehicleState
{
    Stationary, Idle, Moving
}

O estado é um substantivo tão generalizado, não seria melhor descrever a que estado ele se refere? Como eu fiz acima

O exemplo de tipo também na minha opinião não se refere ao tipo de leitor, mas ao seu banco de dados. Eu preferiria que você estivesse descrevendo o produto de banco de dados do leitor que não é necessariamente relevante para o tipo de leitor (por exemplo, o tipo de leitor pode ser apenas encaminhado, armazenado em cache e assim por diante). assim

reader.Database = Databases.Oracle;

Na realidade, isso nunca acontece, pois eles são implementados como drivers e uma cadeia de herança em vez de usar enums, e é por isso que a linha acima não parece natural.

Chris S
fonte
24
Meu entendimento é que os sinalizadores devem ser pluralizados, não simples enums.
Serge Wautier
8
em relação à remoção de enums da classe, ainda não entendi por que CarState é mais conveniente do que Car.State. No entanto, não entendo o lado positivo de obter um enum de uma classe quando este enum descreve o comportamento dessa classe apenas.
Serge Wautier
Eu deveria ter escrito frases nominais como FileOptions, não apenas substantivos, atualizei a resposta. Suponho que classname.Enum é apenas uma preferência - não consigo encontrar nenhum exemplo no framework que acabe copiando.
Chris S
Embora a MS diga que o plural deve ser mantido para sinalizadores, com o tempo, passei a gostar cada vez mais dessas soluções. Agora também o uso para enums. Portanto, mudei de ideia e aceitei sua resposta em vez da de Filip.
Serge Wautier
1
Eu sei que estou 1 ano e meio atrasado aqui, mas public class EngineStatedeveria estar public enum EngineStateno exemplo, certo?
David Murdoch,
36

A definição de "Desligado", "Iniciando" e "Movendo-se" é o que eu chamaria de "Estado". E quando você está insinuando que está usando um "Estado", esse é o seu "Status". Assim!

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

  State state = State.Off;

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

Se pegarmos outro exemplo daquele declarado, em que você gostaria de usar a palavra "Tipo", como neste caso:

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

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

}

Você realmente precisa ver que há uma diferença entre enums e enums, certo? Mas ao criar um framework ou falar sobre arquitetura você precisa focar nas similaridades, ok vamos encontrá-las:

Quando algo é definido como um estado, é definido como o status de "coisas"

Exemplo: o status do carro é Running State, Stopped State e assim por diante.

O que você deseja alcançar no segundo exemplo é um pouco isto:

myDataReader.Type = DataReader.Database.OleDb

Você pode pensar que isso vai contra o que tenho pregado aos outros, que você precisa seguir um padrão. Mas você está seguindo um padrão! O caso Sql também é um caso específico e, portanto, precisa de uma solução um tanto específica.

No entanto, o enum seria reutilizável em seu System.Data espaço, e é disso que tratam os padrões.

Outro caso para examinar com o "Tipo" é "Animal", onde o Tipo define as Espécies.

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

        public Type Species{ get; set; }

    }

Isso está seguindo um padrão, você não precisa especificamente "conhecer" o objeto para isso e não está especificando "AnimalType" ou "DataReaderType", você pode reutilizar os enums em seu namespace de escolha.

Filip Ekberg
fonte
1
Acredito que o nome "Status" seja apenas um exemplo. E quanto a outras situações, quando você não pode confiar no Status / Estado? Por exemplo, um tipo enum ...
Dan C.
Você poderia fornecer um cenário de exemplo para isso? tentarei expandir minha resposta de acordo com isso também :)
Filip Ekberg
2
@Filip: o exemplo Animal Type mostra exatamente o que eu quis dizer no primeiro comentário, ou seja, isso é basicamente uma "reformulação" do enum. Usar sinônimos para o enum e o nome da propriedade torna o código um tanto confuso, eu acho.
Dan C.
1
Eu também acho que 'espécie' é apenas uma reformulação do tipo (para animais, neste caso).
LegendLength
2
Simplesmente renomear nem sempre é tão simples - pense em uma classe para uma carta de jogo, por exemplo, com um naipe de enum e um naipe de propriedade - renomear para o que exatamente? Desajeitado de qualquer maneira.
annakata,
9

Acho que o verdadeiro problema aqui é que o enum Status está encapsulado dentro de sua classe, de forma que Car.Statusé ambíguo tanto para a propriedade Statusquanto para o enumStatus

Melhor ainda, coloque seu enum fora da classe:

public enum Status
{
    Off,
    Starting,
    Moving
}

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

ATUALIZAR

Devido aos comentários abaixo, explicarei meu projeto acima.

Eu não acredito que enums ou classes ou qualquer outro objeto deva residir dentro de outra classe, a menos que seja totalmente privado dentro dessa classe. Veja o exemplo acima, por exemplo:

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

Embora alguns comentaristas possam argumentar que Status não tem nenhum significado fora do escopo da classe Car, o fato de você estar definindo um público propriedade significa que há outras partes do programa que vai usar essa enumeração:

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

E isso para mim é um cheiro de código. Se vou olhar para esse status fora de Car, posso muito bem defini-lo fora também.

Como tal, provavelmente irei apenas renomeá-lo como:

public enum CarStatus
{...}

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

No entanto, se esse enum for usado dentro e apenas dentro da classe car, então estou bem em declarar o enum lá.

Jon Limjap
fonte
Isso tornaria o Status global, você pode querer tê-lo apenas dentro de uma área específica. "Status" para outros tipos como "Humano" pode não ter "Iniciando". Mas você deve seguir um padrão.
Filip Ekberg
Não, ele está certo. O enum é em 99% dos casos a mesma palavra que você deseja usar para a propriedade. Um enum é apenas um sinalizador com nome, portanto, faz pouco mal em viver fora (ao contrário das classes que contêm lógica)
Quibblesome
Jon, este é exatamente o meu ponto: o enum Status é significativo apenas em relação a Car. Tipos de objetos totalmente diferentes terão status totalmente diferentes
Serge Wautier
eles estarão em namespaces diferentes, então não importa
Chris S
A explicação de que querer olhar para fora do Carro faz sentido. Mas, no meu caso, tenho duas classes ORe CR. Ambos têm seu próprio conjunto de estados, portanto, não é uma opção defini-los fora de seu próprio escopo.
deed02392 de
4

Sei que minha sugestão vai contra as convenções de nomenclatura do .NET, mas pessoalmente prefixo enums com 'E' e os sinalizadores de enum com 'F' (semelhante a como prefixamos as interfaces com 'I'). Eu realmente não entendo porque esta não é a convenção. Enums / Flags são um caso especial, como Interfaces, que nunca mudam seu tipo. Isso não apenas deixa claro o que é, como também é muito fácil de digitar em intellisense, pois o prefixo filtrará a maioria dos outros tipos / variáveis ​​/ etc, e você não terá esses conflitos de nomenclatura.

E isso também resolveria outro problema em que, para exemplos no WPF, eles usam classes estáticas como enums (por exemplo, FontWeights) que têm instâncias predefinidas de tipos, mas você não saberia se não procurasse por eles. Se eles apenas os prefixassem com 'E', tudo o que você teria que fazer é digitar no caractere para encontrar essas classes estáticas especiais.


fonte
4

Os odiadores da notação húngara e suas variantes que se danem. Eu uso uma convenção de enums com sufixo - espere por isso - Enum. Conseqüentemente, nunca tenho o problema que você descreve, perco tempo me preocupando sobre como chamá-los e o código é legível e autodescritivo para inicializar.

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

  public StatusEnum Status { get; set; }

}
Nathanchere
fonte
9
Esteja ciente de que as convenções da Microsoft para Enumerações de Nomenclatura dizem: X NÃO use um sufixo "Enum" em nomes de tipo de enum.
DavidRR
2
Porque as convenções da Microsoft comprovaram que resistem ao teste do tempo.
nathanchere
2

Eu mudaria o nome da propriedade para algo como "CurrentStatus". Rápido e fácil :)

TWith2Sugars
fonte
1

Eu sugiro adicionar "Opção" ao nome do tipo (ou Sinalizador se ele contiver sinalizadores de bit), ou seja, o tipo é Car.StatusOption e a propriedade é Car.Status.

Em comparação com a pluralização, isso evita colisões de nomenclatura ao criar coleções do tipo enum, em que você normalmente deseja pluralizar a propriedade da coleção , não o tipo enum .

Kristian Wedberg
fonte
0

Normalmente prefixo os enums, por exemplo, CarStatus. Suponho que tudo depende da equipe com a qual você está trabalhando (se houver regras / processos para esse tipo de coisa) e do uso dos objetos. Apenas meus 2 centavos (:

Kieron
fonte
1
Isso acabaria com a convenção de nomenclatura com MyObjectName na frente de Status.
Filip Ekberg
o namespacing da classe deve ser suficiente para lidar com isso de qualquer maneira
annakata