2010-10-26 11 views
6

considerar los siguientes ::¿Por qué las enums de unboxing producen resultados extraños?

Object box = 5; 
int @int = (int)box; // int = 5 
int? nullableInt = box as int?; // nullableInt = 5; 
StringComparison @enum = (StringComparison)box; // enum = OrdinalIgnoreCase 
StringComparison? nullableEnum = box as StringComparison?; // nullableEnum = null. 

2 cosas ::

  1. ¿Por qué puedo unbox a StringComparison? Supongo que esto se debe a que su tipo subyacente es Int32, pero aún así me parece extraño.
  2. ¿Por qué nullableEnum tiene un valor de nulo?

Como tengo entendido, el único unboxing válido es de un tipo de valor encuadrado en su tipo o en un tipo anulable. Si int puede desempaquetar a Enum, entonces ¿por qué no ocurre lo mismo con los valores que aceptan nulos? Del mismo modo, si en vez de 5 encasillé StringComparison.OrdinalIgnoreCase, sería nullableInt nulo, pero nullableEnum no lo sería.

Respuesta

2

Estrictamente hablando, yo creo que es un error endetalle de implementación de el tiempo de ejecución, ya que la especificación C# dice

Unboxing a un tipo anulable produce el valor nulo de la nullable- escriba si el operando fuente es nulo, o el resultado envuelto de unboxing la instancia del objeto al tipo subyacente del tipo anulable en caso contrario.

Es decir, si unboxing a StringComparison funciona, entonces unboxing a nullable <StringComparison> debería funcionar también. No está claro si ambos deberían funcionar o si ambos deberían fallar. La especificación dice que

Para una conversión unboxing a un tipo no anulable-valor dado para tener éxito en tiempo de ejecución, el valor del operando fuente debe ser una referencia a un valor en caja de la que no anulable -tipo de valor.

Debe decidir si un int encuadrado se considera un valor encasillado de tipo StringComparison porque el tipo subyacente de StringComparison es int. La especificación continúa diciendo que se genera una InvalidCastException si el cuadro contiene un "objeto incompatible".Un int es ciertamente "compatible" con StringComparison, ya que puede copiar de forma segura los cuatro bytes del montón en su variable StringComparison.

+1

Re: error en el tiempo de ejecución: no diría que es un * error * en el tiempo de ejecución; más bien, el tiempo de ejecución es en algunos casos más indulgente de lo que requiere la especificación C#. Solo a un costo excesivo podemos restringir el comportamiento de la implementación de C# para que sea una implementación estricta de la especificación, sin ganancia real. –

+1

Re: tipos "compatibles": sí, esto es un poco de agitar la mano en la especificación. Las reglas CLR son ligeramente inconsistentes. Es interesante, por ejemplo, que aunque int y uint se consideran tipos compatibles en el CLR a los efectos de la covarianza de matriz, no se consideran tipos compatibles en el CLR a los efectos de unboxing, aunque int y enum sí lo son. –

+0

Punto justo, "error" es un poco duro. Estaba leyendo el primer bit citado como "unboxing to int? Debería funcionar cuando unboxing to int works", cuando es realmente "unboxing to int? Debería funcionar cuando unboxing to int * should * work". En realidad, mi punto era que la especificación concuerda con la intuición de Michael y que los diferentes resultados son un "accidente" de la indulgencia del tiempo de ejecución en lugar de una decisión de diseño deliberada de que el unboxing a las enumeraciones anulables no debería ser válido. – stevemegson

-1

1) Sí, el tipo subyacente de enum es int y es por eso que funciona de esta manera. Aún más. Puede hacer lo siguiente:

enum MyEnum 
{ 
    One = 1, 
    Two = 2, 
} 

int i = 3; 
MyEnum myEnum = (MyEnum)i; // This works without exceptions. 

2) Debido a que es en realidad StringComparison?Nullable<StringComparison> que es de tipo diferente. Y el operador as solo comprueba si el objeto es del mismo tipo que el especificado en el operador.

+0

Sí, pero también puede hacer 'long @long = (long) intVar;' esto no significa que puede destrabar un int a un largo. –

1

Cuando lanza enum o entero para objetar, aún contiene información de tipo. Entonces box is StringComparison devolverá false. Pero está permitido lanzar cualquier enumeración o int a cualquier enumeración, por lo que funciona explícitamente el molde (StringComparison)box. Es un caso especial para enums. Nullable<T>, por otro lado, es solo una clase habitual, T no se maneja de ninguna manera específica cuando echas o revisas el tipo. Esta es la razón por la cual este código emitirá una excepción.

 StringComparison? nullableEnum = (StringComparison?)nullableInt; 
Cuestiones relacionadas