2010-02-13 9 views
23

Hay algunas preguntas relacionadas here y here, pero realmente no me dieron respuestas satisfactorias. El problema es que los enumerados anidados en una clase en C# no pueden tener el mismo nombre que una propiedad de la clase. Mi ejemplo:Enumerados y conflictos de nomenclatura de propiedades

public class Card 
{ 
    public enum Suit 
    { 
     Clubs, 
     Diamonds, 
     Spades, 
     Hearts 
    } 

    public enum Rank 
    { 
     Two, 
     Three, 
     ... 
     King, 
     Ace 
    } 

    public Suit Suit { get; private set; } 
    public Rank Rank { get; private set; } 
    ... 
} 

Hay algunas opciones para hackear esto, pero no me parecen correctas.

Podría mover las enumeraciones fuera de la clase, pero solo diría Suit en lugar de Card.Suit, lo cual me parece incorrecto. ¿Qué es un Suit fuera del contexto de un Card?

que podía moverlos fuera de la clase y cambiarlos a algo así como CardSuit y CardRank, pero entonces me siento que estoy horneando información de contexto en el nombre de la enumeración, cuando esto debe ser manejado por una clase o nombre del espacio de nombres.

Podría cambiar los nombres de las enumeraciones a Suits y Ranks, pero esto infringe Microsoft's naming guidelines. Y simplemente no se siente bien.

Podría cambiar los nombres de las propiedades. Pero a que? Me parece intuitivamente correcto querer decir Suit = Card.Suit.Spades.

Podría mover las enumeraciones en una clase estática separada llamada CardInfo que contiene solo estas enumeraciones. Si no puedo encontrar otra cosa, creo que esta es la mejor opción.

Así que me pregunto qué han hecho otras personas en situaciones similares. También sería bueno saber por qué esto no está permitido. ¿Tal vez Eric Lippert o alguien podría intervenir en la decisión de prohibirlo? Parece que solo crea la ambigüedad dentro de la clase, y esto podría resolverse forzando el uso de this.Suit para el nombre de la propiedad. (Similar a la desambiguación entre los lugareños y los miembros.) Supongo que esto se dejó de lado debido a la cosa "every feature starts with -100 points", pero me gustaría tener curiosidad sobre las discusiones al respecto.

+1

Gracias por sus comentarios, a todos. Voy con 'CardInfo', pero no creo que haya una respuesta canónica aquí. Hay muchas opciones decentes, y creo que todo se reduce al estilo. –

+0

Anidar 'enum' está bien si va a usarlos solo (¿en su mayoría?) Dentro de la clase. Luego debe nombrar 'enum' * ligeramente * de manera diferente (agregando * Tipo *, * Modo *, * Opción *, etc. al nombre) para evitar conflictos de nombre con el campo/propiedad. Si habrá muchos usuarios de ese 'enum' fuera de la clase, entonces anidar es una mala idea. Puede declararlo en el mismo archivo cs (para tener al menos algún tipo de relación con la clase donde se usa). El anidamiento no es deseable en wpf también (no necesariamente 'enum', pero en general). – Sinatr

Respuesta

18

también sería bueno saber por qué esto no está permitido. ¿Tal vez Eric Lippert o alguien podría intervenir en la decisión de prohibirlo?

El objetivo de la regla es garantizar que no exista ambigüedad dentro de la clase al buscar un nombre. Ciertas regiones de código se designan para definir un 'espacio de declaración'. La regla fundamental de espacios Declaración es no hay dos cosas declaradas en el mismo espacio de declaración tienen el mismo nombre (a excepción de los métodos, los cuales deben diferir en firma, no nombre.)

Hacer excepciones a esta regla simplemente hace las cosas más confusas, no menos confusas. Estoy de acuerdo en que es molesto que no puedas tener una propiedad y una enumeración del mismo nombre declaradas en el mismo espacio de declaración, pero una vez que comienzas a hacer excepciones, se convierte en un desastre. Por lo general, es una buena propiedad que un nombre singularmente identifique un grupo de métodos, un parámetro, una propiedad, etc.

Tenga en cuenta que esta regla se aplica a las cosas declaradas en un espacio de declaración, no cosas utilizados en un espacio de declaración. Es perfectamente legal decir "traje de traje público {get; set;}" siempre que el traje de tipo no se declare en el mismo espacio de declaración que la propiedad. Cuando alguien dice "Suit.X", averiguar si X está en el tipo (es decir, X es un miembro estático) o la propiedad (es decir, X es un miembro de instancia) es un poco complicado. Véase mi artículo sobre cómo lo hacemos para más detalles:

http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx

+0

Eso tiene sentido para mí. Gracias por la info! –

+0

¿Existe algún tipo de convención de nomenclatura estándar para tratar este problema? En mi caso particular, intento crear una estructura de clase anidada para contener los valores de un archivo de configuración jerárquico (json). Mi tendencia natural sería nombrar las propiedades igual que la clase anidada (por ejemplo, si tengo una clase anidada 'Settings.Color', me gustaría tener' public Color Color {get; set;} '), pero por supuesto, esto no se compilará. Mis opciones parecen ser cambiar el nombre de la clase o la propiedad, por ejemplo, 'ColorInfo', pero esto podría dar lugar a nombres desagradables para los elementos que se encuentran en lo más profundo de la jerarquía. – devuxer

+0

@devuxer: No conozco una buena manera de resolver ese problema, pero generalmente no es motivo de gran preocupación, ya que se considera un mal olor para hacer un tipo anidado público. Si el tipo anidado no es público, entonces nunca tendrá una propiedad pública que exponga el tipo así. Evitaría los tipos anidados; Solo los uso cuando el tipo anidado es un detalle de implementación privada del tipo externo. –

3

Prefiero poner nombre a las enumeraciones usando un sustantivo seguido de Opciones. En su caso:

SuitOptions 
RankOptions 

Después de todo, la enumeración es sólo un conjunto de posibles opciones, ¿verdad?

Usted tendrá entonces:

myCard.Suit = Card.SuitOptions.Clubs; 

que en mi opinión tiene sentido y que todavía es capaz de saber cuando se visualiza el texto a continuación, si es de enumeración o propiedad.

+1

Dado que una enumeración es un conjunto de opciones por definición, parece redundante incluir eso en el nombre. Parece equivalente a agregar un sufijo -Enum, que las pautas de estilo dicen que no se debe hacer. –

+0

Estoy de acuerdo en que agregar el sufijo -Enum es redundante pero sigo creyendo que -Options es una buena opción porque: describe qué es ese tipo mientras que "Suits" me hará pensar en una colección de trajes y el simple "Suit" no es trabajando en este contexto. –

+1

¿Hay alguna enumeración donde pienses que "Opciones es un sufijo inapropiado"? No puedo pensar en ningún lugar donde * no * encaje, que creo que es el problema, es demasiado general. Es como -Manager o -Helper en una clase. –

1

Movería las enumeraciones fuera de la definición de clase y usaría el espacio de nombres para indicar que se relacionan con las tarjetas. Generalmente no me gustan los enumerados anidados dentro de las clases. Sin embargo, tienes razón acerca de la pluralidad: singular para enumeraciones regulares, plural para enumeraciones de banderas.

+0

Esa es otra opción, pero rápidamente se encuentra con problemas similares. ¿Cómo debe llamarse el espacio de nombre? 'Card' está fuera, ya que entraría en conflicto con el nombre de la clase. Podrías anidarlo en otro nivel en un espacio de nombres de "Enums", supongo. Algo así como 'Core.Enums.Card' donde la clase en sí misma es' Core.Card'. Esa no es una mala opción. –

1

Tus enumeraciones son básicamente tipos de datos que has definido. No usaría 'int' o 'cadena' como nombre de miembro, por lo que creo que es una idea igualmente mala utilizar los nombres de sus enumeraciones y nombres de miembros en su caso.

+0

Entonces, ¿cómo los nombrarías en este caso * específico *? 'int' y' string' son cosas muy generales, pero 'Suit' y' Rank' solo son significativas en el contexto de una 'Tarjeta'. –

+0

Realmente lo odio cuando una posición filosófica perfecta se tropieza con la realidad práctica :) En mi propio esquema de nombres, siempre utilizo camelCase para los nombres de mi propiedad, por lo que mi declaración de propiedad sería por "traje de traje público" que estaría bien . Si no puede hacer eso, me gusta su idea de clase CardInfo. Y CardSuit (como sugeriste) o SuitOptions (de Victor) tampoco están mal. De vez en cuando, supongo que un nombre agradable y lógico del mundo real para nuestros objetos no encaja con lo que el compilador nos permite hacer. – Ray

+0

Es cierto. Aquí hay algunas opciones decentes en las respuestas, pero ninguna se siente * ideal *. Me estoy inclinando hacia mi cosa de 'CardInfo', pero lo haría, ¿no? Lo sugerí, después de todo. Creo que esto es en gran medida una elección de estilo. –

3

Estoy de acuerdo con mover la definición de enumeración a un lugar separado.Actualmente, las enumeraciones son accesibles solamente a través de la tarjeta, por lo que si se quería comprobar si hay un as, que tendrían que hacer

if (card.CardSuit == Card.Suit.Ace) { } //need different name for Suit field 

Donde si la trasladó a una definición por separado, se puede hacer esto si lo hizo mundial:

if (card.Suit == Suit.Ace) { } //no naming clashes, easier to read 
+1

Deben evitarse los tipos/enumeraciones anidados si se van a usar con frecuencia. Por ejemplo, son difíciles de descubrir a través del IDE/Intellisense porque incluso cuando escribe "Suit" no obtendrá el mensaje para agregar automáticamente el "uso", ya que debe acceder a la enumeración como "Card.Suit" como en Loco exmaple. Nombra un tipo solo si se usa solo internamente dentro de la clase, si se necesita externamente muy raramente o si solo se usa en escenarios avanzados como heredar la clase. – AaronLS

Cuestiones relacionadas