2011-01-18 8 views
19

No hay pérdida de datos al hacer esto, así que ¿cuál es el motivo para tener que enviar explícitamente enumeraciones a ints?¿Por qué las enumeraciones requieren un molde explícito para el tipo int?

¿No sería más intuitivo si era implícita, por ejemplo cuando se tiene un método de nivel superior como:

PerformOperation (OperationType.Silent type) 

donde PerformOperation llama a un método envuelta C++ que está expuesta como tal:

_unmanaged_perform_operation (int operation_type) 

Respuesta

43

Hay dos usos principales e inconsistentes de enumeraciones:

enum Medals 
{ Gold, Silver, Bronze } 

[Flags] 
enum FilePermissionFlags 
{ 
    CanRead = 0x01, 
    CanWrite = 0x02, 
    CanDelete = 0x04 
} 

En el primer caso, no tiene sentido para tratar estas cosas como números. El hecho de que se almacenan como enteros es un detalle de implementación. No puede lógicamente agregar, restar, multiplicar o dividir Oro, Plata y Bronce.

En el segundo caso, también no tiene sentido tratar estas cosas como números. No puede sumar, restar, multiplicar o dividir. Las únicas operaciones sensatas son operaciones bit a bit.

Las enumeraciones son números pésimos, por lo que no debería poder tratarlos como números accidentalmente.

+1

¿Qué hay de convertir implícitamente una enumeración a su tipo de valor subyacente cuando se especifica explícitamente? es decir, "enum FilePermissionFlags: int" podría convertir implícitamente a int. – Lazlo

+7

@Lazlo: ¿Y cómo se dice lo que había en el código fuente cuando la enumeración se cargó sin metadatos? Es algo muy extraño para cambiar el comportamiento. Realmente, lo que hubiera sido mejor en mi opinión eran tipos realmente enumerados para cosas como "Medallas", que no son convertibles a ningún tipo de entero, y un tipo especial de entero que es un "indicador uint" que tiene las operaciones bit a bit en él . El hecho de que los enteros se combinen con números pequeños * y * pequeños conjuntos de bits solo parece normal porque crecimos con él; de hecho, es realmente asqueroso. –

+0

@Eric Lippert: ¿No hay ninguna marca posible para tal caso? Trabajas con el compilador diariamente, supongo. En cuanto a las banderas de bits, estoy de acuerdo. – Lazlo

5

Porque las enumeraciones no tienen que ser int basado:

La palabra clave enum se utiliza para declarar una enumeración , un tipo distinto que consta de un conjunto de constantes con nombre llamado lista de enumerador. Cada tipo de enumeración tiene un tipo subyacente, que puede ser cualquier tipo integral excepto char.

para que pueda hacer algo como esto:

enum Something :long { valueX = 0, valueY = 2147483648L } 
+0

Tienes razón, pero el compilador podría averiguar si la enumeración está basada en int y permitir esto, o forzar e int enum basado por otros medios? –

+0

Alternativamente, podría tratar de convertir siempre implícitamente al tipo del primer miembro. –

+2

Claro que el compilador * podría * - pero ¿cuál es el significado de 'valueY - valueX'? ¿Qué pasa si los nombres son 'Azul' y' Cuadros'Si usa enums como enteros tan a menudo que un lanzamiento explícito es una carga, quizás deba cuestionar su diseño. –

2

¿Por qué dices sin pérdida de datos? No todas las enumeraciones son ints, después de todo. Deben ser de tipo entero, pero eso puede significar byte, ulong, etc.

Como un caso de esquina, el literal 0 es implícito, pero; ¿Cuál sería tu caso de uso aquí?

Es bastante raro que necesite hacer esto, generalmente importación de datos, etc. Un elenco ocasional de no-operatoria tiene perfecto sentido para mí y evita errores accidentales.

+0

Gracias, no estoy seguro de lo que quiere decir en su segundo párrafo. 0 puede ser lanzado implícitamente a una enumeración? –

+2

@Joan: La especificación dice que cualquier * literal cero * es convertible a cualquier enumeración, por lo que está garantizado que podrá inicializarlo a su valor predeterminado incluso si no hay ningún valor cero definido en la enumeración. El compilador realmente permite cualquier * constante cero *. Consulte http://blogs.msdn.com/b/ericlippert/archive/2006/03/28/563282.aspx y http://blogs.msdn.com/b/ericlippert/archive/2006/03/29/the -root-of-all-evil-part-two.aspx por los horribles detalles. –

+0

@Eric: Gracias, lo tengo ahora. Tampoco tengo claro el primer párrafo de Marc. Entonces, las enumeraciones se basan en si los miembros son cadenas o cualquier otro tipo. Al igual que los miembros se almacenan como ints? –

1

Esa es la forma en C# funciona ...

Si Enum había heredado de int, entonces esto debería ser posible. Enum no hereda de int, y por lo tanto, se requiere un molde.

La única forma de que las clases de conversión implícita sean heredadas.

2

¿No sería más intuitivo si era implícita, por ejemplo cuando se tiene un método de nivel superior como:

En realidad no creo. En este caso, estás tratando de usar un Enum en un caso extremo.

Sin embargo, si las enumeraciones se convirtieran implícitamente a valores enteros, esto reduciría drásticamente su efectividad. Al forzar una conversión int explícitamente, el compilador trata a enum como un tipo especial, una de muchas opciones, no como un entero. Esto demuestra más claramente la intención de la enumeración, y reduce la posibilidad de errores del programador (es decir, la asignación de valores que no están definidos en la enumeración a una variable enum, etc.).

Personalmente me alegra que enum in C# sea más que (efectivamente) un valor int constante.

0

Como han dicho otros, es imposible cambiar el modelo requerido de EnumType a int. Sin embargo, hay varias soluciones. Por ejemplo, tengo varias enumeraciones que se refieren a cosas similares, y quería poder asignar cualquiera de ellas a una variable. Así que fui con:

public ValueType State { 
    get { 
     return state; 
    } 
    set { 
     state = (int)value; 
    } 
} 

y por lo tanto, podría decir tanto playerObject.animator.State = Player.STANDING y monsterObject.animator.State = Monster.DROOLING, de manera implícita en cuanto a la clase de llamada podría contar.

Además, sí, hay una razón legítima por la que tengo que tratar los valores enum como números.

1

Creo que la respuesta a "¿Por qué las enumeraciones requieren un molde explícito para el tipo int?" es que las enumeraciones fuertemente tipadas según C# son una defensa útil contra errores de programación comunes.

Imagínese que tenía una aplicación de gestión de la pintura, sobre la base de dos enumeraciones:

enum Textures { Gloss, Satin, Matt }; 
enum Colors { White, Green, Red, Blue, Brown }; 

y un método sala de pintura de la siguiente manera:

private void PaintRoom (Textures texture, Colors color) 

En un lenguaje con tipos fuertes enumeración como en C# , un comando como este:

// nonsensical attempt to have texture=White and color=Matt 
PaintRoom(Colors.White, Textures.Matt); 

... harían un error en tiempo de compilación (no se puede poner color i nto donde se espera una textura y viceversa). Pero en los idiomas donde las enumeraciones no son fuertemente tipadas y/o pueden ocurrir conversiones implícitas (incluyendo C y C++), tanto nuestro Colors como nuestro Textures se pueden tratar como int, así que podemos emitir un comando PaintRoom(Colors.White, Textures.Matt) y compilaremos bien, pero terminamos con una habitación pintada de Rojo Brillante (0, 2) en lugar del Blanco Mate (2, 0) que pretendíamos y el código en una mirada rápida parece decir.

Las enumeraciones fuertemente tipadas son, en su mayoría, algo bueno, para evitar que personas accidentalmente pongan enums en lugares para los que no estaban destinados. Y donde alguien realmente quiere su enumeración como int, C# obliga al codificador a dejar clara su intención al insistir en una conversión explícita.

Cuestiones relacionadas