2010-06-30 23 views
23

Acabo de descubrir un error sutil donde tuve una enumeración con dos nombres que comparten el mismo valor numérico (en este caso rojo = 10 y rojo = 10). Estoy un poco sorprendido de que este no sea un error de sintaxis.¿Por qué está bien que una enumeración tenga dos nombres diferentes con el mismo valor numérico?

public enum Colour 
{ 
    Red=10, 
    Blue=11, 
    Green=12, 
    Crimson=10 
} 
// Debug.Write(Colour.Red==Colour.Crimson) outputs True 

¿Hay alguna razón real por qué este comportamiento podría ser un útil o sí creo que debe ser un error de sintaxis?

+2

Pensé que era tan inteligente por pensar en preguntar esto más de tres años después de que se le preguntó originalmente. – MrBoJangles

+0

Consulte las pautas de MSDN para el diseño enum: http://msdn.microsoft.com/en-us/library/ms229058.aspx En el espíritu de esto, diría que, aunque técnicamente es posible, es probable que no recomendado. – Technobabble

+2

@MrBoJangles, luego volvería a preguntar lo mismo 16 meses después de ti. –

Respuesta

36
public enum Colour 
{ 
    Red=10, 
    Rouge=10, 
    Blue=11, 
    Bleu=11, 
    Green=12, 
    Vert=12, 
    Black=13, 
    Noir=13 
} 
+0

Respuesta muy concisa y efectiva. –

+0

De acuerdo. Directamente al punto, no se necesita explicación. – Gage

+10

¿Y cómo usarías eso? En un equipo de programación multilingüe, ¿cada miembro elige sus propias constantes? –

4

Enum es la enumeración de las variables constantes, y se puede tener dos elementos con el mismo valor, no hay ninguna razón para ser un error de sintaxis Creo, sin embargo, esto hará que compilar error en el código

switch(c) 
{ 
    Colour.Red: 
    break; 
    Colour.Crimson: 
    break; 
    ... 
} 
+0

Vale la pena saber esto. Es una razón para no usar nombres compartidos deliberadamente. – AndyM

+0

De acuerdo; dos nombres con el mismo valor no es un error. Si desea evitarlo, no especifique los valores numéricos. –

0

He visto lo mismo en un contenedor .NET TWAIN: permite que todos los códigos de mensajes TWAIN se almacenen en una gran enumeración, pero al principio hace que las cosas sean un poco confusas.

9

Los registros se usan como constantes y definitivamente puede tener dos constantes con el mismo valor que se usan en los mismos lugares. Puede ser así debido a la API de terceros, debido a la compatibilidad con versiones anteriores o simplemente debido a las reglas comerciales.

1

Está bien. Podría tener dos valores que son diferentes desde el punto de vista del usuario de una API, pero funcionalmente pueden tratarse como el mismo valor.

3

No es un error de sintaxis. Todo lo que hace un enum es enumerar una serie de constantes de manera fuertemente tipada.

Por lo tanto, si un desarrollador escribe mal (como en su ejemplo), en lo que respecta al CLR, ese es un caso perfectamente válido. El CLR supone que el desarrollador sabe lo que hace y por qué eligió hacerlo.

En cuanto a los casos del mundo real, no se me ocurre ninguna por el momento, pero estoy seguro de que probablemente haya ocasiones en las que sería útil.

2

Claro que sí, aunque quizás no sea demasiado común. Si hay una entidad/valor que comúnmente se conoce bajo dos nombres diferentes, esa es una buena razón.

El escenario que ha presentado es quizás uno de estos casos. Una aún mejor, directamente desde el BCL, es la enumeración System.Windows.Forms.MessageBoxIcon; los miembros Stop, Error y Hand tienen la misma descripción y, de hecho, el mismo valor. Asterisk y Information también son idénticos, como lo sugieren los comentarios:

Asterisk The message box contains a symbol consisting of a lowercase letter i in a circle. 
Information The message box contains a symbol consisting of a lowercase letter i in a circle. 

Esperamos que esto te dará una buena idea de escenarios apropiados (su propia siendo probablemente uno).

19

he visto que esta característica se utiliza a veces para un valor "default":

public enum Scope 
{ 
    Transient, 
    Singleton, 
    Default=Transient 
} 

Pero atención, esto es sólo azúcar para el usuario de su enumeración. El hecho de que se llame Predeterminado no significa que sea el valor inicial.

1

Usar por valor con nombre en contraposición con el valor real es root. Supongamos que tiene francés, inglés, etc. con el mismo valor. Esta es la raíz de enum para mí.

6

From the c# language spec:

miembros de enumeración múltiples pueden compartir el mismo valor asociado. El ejemplo

enum Color 
{ 
    Red, 
    Green, 
    Blue, 
    Max = Blue 
} 

muestra una enumeración en la que dos miembros de la enumeración, Azul y Máx, tienen el mismo valor asociado.

En este caso, podría verificar MyColor == Color.Max que sería útil en algunas circunstancias.

+2

Max es un ejemplo de un valor sentinal. Esto no se recomienda según las pautas de diseño de MSDN para enumeraciones porque viola la separación de preocupaciones entre el valor bruto y su estado. Si alguna vez surge la necesidad de cambiar lo que se considera Max, cualquier referencia que espere que Max siempre iguale a Azul debería ser reparada. – Technobabble

0

Se recomienda a veces (aunque no recomendado por EM para C# - véase el comentario de Salaros) para incluir un límite inferior y superior en su enumeración como

public enum Colour 
{ 
    LowBound=10, 
    Red=10, 
    Rouge=10, 
    Blue=11, 
    Bleu=11, 
    Green=12, 
    Vert=12, 
    Black=13, 
    Noir=13, 
    UpperBound=13 
} 

A los efectos de la validación/iteración a través de cada posible configuración. Aunque tengo la sensación de que .Net puede proporcionar una facilidad para esto :)

+1

El final de la enumeración es un límite en sí mismo y puede iterarlo en orden de declaración: foreach (Foos foo en Enum.GetValues ​​(typeof (Foos))) En realidad, se recomienda evitar los valores de enumeración centinela (LowBound, UpperBound) http://msdn.microsoft.com/en-us/library/vstudio/ms229058%28v=vs.100%29.aspx – Salaros

+0

Estaba dando un ejemplo de dónde varios elementos pueden compartir un valor. En algunos idiomas, no puede iterar una enumeración con foreach. Apenas merece un -1 pero ¡no importa! –

+1

Estamos hablando de C# y no de "otros" idiomas, por lo que si le enseñas a alguien a codificar contra las especificaciones oficiales que mereces -1. De esta manera, los novatos de C# no aprenderán a adelgazar mal en C#. De todos modos, tenga en cuenta que -1 se aplica a ambas cuentas, así que esto no es trolling: solo estoy sacrificando mis puntos para mejorar el stackoverflow ... esto es lo que todos deberíamos hacer. – Salaros

0

Creo que hay muchos usos para volver a utilizar el mismo número. Para dar un ejemplo nuevo, digamos que tiene un sistema de clasificación que asegurará que los objetos de una clase en particular (Padres) se creen antes que otras clases que dependen de ellos (Niños), es posible que tenga algunos niños que estén en el mismo "nivel" 'y no importa cuál se crea primero. En el siguiente ejemplo, primero se creará el padre, primero el hijo 1, 2 o 3, y luego el último será Child4. Si esto se viera como un diagrama de árbol, cualquier elemento con el mismo número sería 'hermanos'.

public enum ObjectRanks 
{ 
    Parent = 0, 
    Child1 = 1, 
    Child2 = 1, 
    Child3 = 1, 
    Child4 = 2 
} 

Aunque puedo ver su punto de vista en que esto podría ser fácil de hacer por error. En ese caso, sería útil si Visual Studio tuviese la opción de habilitar advertencias que le permitieran compilar, pero generaría una advertencia si el mismo número se usara dos veces.

21

¡Cuidado! Si su enum tiene varios elementos con el mismo valor, puede obtener resultados inesperados cuando usa Enum.Parse(). Al hacerlo, se devolverá arbitrariamente el primer elemento que tenga el valor solicitado. Por ejemplo, si tiene enum Car { Ford = 1, Chevy = 1, Mazda = 1}, entonces (Car)Enum.Parse(typeof(Car), "1") devolverá Car.Ford. Si bien eso podría ser útil (no estoy seguro de por qué lo sería), en la mayoría de las situaciones probablemente sea confuso (especialmente para los ingenieros que mantienen el código) o se pasa por alto fácilmente cuando surgen problemas.

+0

Gracias por su primera respuesta en SO, y es una buena. ¿Puedo sugerir que se edite el texto para agregar espacio en blanco adicional y, en particular, usar el marcado para resaltar los fragmentos del código? La forma más fácil de hacer esto último es 'rodear el texto' con un backtick (') o usar el botón de citar código en la barra de formato. Sospecho que su recuento de votos puede incluso aumentar si es un poco más fácil de leer. Buena suerte. – Simon

1

Esto es válido y permite referir el mismo valor con diferentes nombres. Tenga cuidado esto funciona bien de una sola dirección. Puede obtener resultados incoherentes si está convirtiendo de int/string a enum o al formatear cadenas.

Ej:

public enum Colour 
{ 
    Red=10, 
    Blue=11, 
    Green=12, 
    Crimson=10 
} 
Colour myColor = Colour.Crimson; 
Console.WriteLine("Crimson is {0}", myColor.ToString()); 

Salida:

Crimson is Red 
0

Este ejemplo muestra por qué esto es útil. Cuando trabajas en una biblioteca pública, que está dedicada al uso público, nombrar las mismas cosas de diferentes maneras puede ser útil.

public enum GestureType 
{ 
Touch = 1, 
Tap = 1, 
DoubleTouch = 2, 
DoubleTap = 2, 
Swipe = 3, 
Slide = 3, 
... 
} 

Cuando diferentes palabras tienen el mismo significado en algunas situaciones, tiene sentido, nombrarlas. Cuando se analiza, siempre devuelve un buen valor en esta situación.

0

I pensaron que sería útil para la asignación de campos, por ejemplo (en LINQPad):

void Main() 
{ 
    ((FieldName)Enum.Parse(typeof(FieldName), "Name", true)).ToString().Dump(); 
    ((FieldName)Enum.Parse(typeof(FieldName), "TaskName", true)).ToString().Dump(); 
    ((FieldName)Enum.Parse(typeof(FieldName), "IsActive", true)).ToString().Dump(); 
    ((FieldName)Enum.Parse(typeof(FieldName), "TaskIsActive", true)).ToString().Dump(); 
} 

public enum FieldName 
{ 
    Name, 
    TaskName = Name, 
    IsActive, 
    TaskIsActive = IsActive 
} 

El objetivo es utilizar el más corto de los nombres, sin embargo los resultados de Parse o TryParse no son consistentes y este código de salidas:

TaskName 
TaskName 
IsActive 
IsActive 
Cuestiones relacionadas