Por que a Unboxing Enums produz resultados estranhos?
Pergunta
Considere o seguinte::
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 coisas ::
- Por que posso desbotar para
StringComparison
? Eu acho que isso é porque o tipo subjacente éInt32
Mas ainda acho estranho. - Porque
nullableEnum
tem um valor de nulo?
Pelo que entendi, o único unboxing válido é de um tipo de valor em caixa é para o tipo ou para um tipo anulável. Se int
pode unbox para Enum
, então por que o mesmo vale para os valores anuláveis? Da mesma forma, se, em vez de 5, eu encaixei StringComparison.OrdinalIgnoreCase
, seria isso nullableInt
seria nulo, mas nullableEnum
não seria.
Solução
Estritamente falando, eu acho que é um Bug in Detalhe de implementação de O tempo de execução, desde a especificação C# diz
A unidade para um tipo anulável produz o valor nulo do tipo anulável se o operando de origem for nulo ou o resultado embrulhado de desbotar a instância do objeto para o tipo subjacente do tipo anulado de outra forma.
Isto é, se unirboxing para StringComparison funciona, então desbota -se para Nullableu003CStringComparison> deve funcionar também. Não está claro se os dois devem funcionar ou ambos falharem. A especificação diz que
Para uma conversão de unboxing para um determinado tipo de valor não nulo para ter sucesso em tempo de execução, o valor do operando de origem deve ser uma referência a um valor em caixa desse tipo de valor não indicado.
Você deve decidir se um INT em caixa é considerado um valor em caixa do tipo StringComparison, porque o tipo subjacente de StringComparison é int. A especificação continua dizendo que um invalidcastException é jogado se a caixa contiver um "objeto incompatível". Um INT é certamente "compatível" com a StringComparison, porque você pode copiar com segurança os quatro bytes da pilha na sua variável StringComparison.
Outras dicas
Quando você lança enum ou número inteiro para se opor, ele ainda mantém informações de tipo. Então box is StringComparison
retornará false
. Mas é permitido lançar qualquer enumeração ou int a qualquer enumeração, tão explícito (StringComparison)box
funciona. É um caso especial para enumes. Nullable<T>
, por outro lado, é apenas uma aula usual, T não é tratada de maneira específica quando você lança ou verifica o tipo. É por isso que esse código lançará exceção.
StringComparison? nullableEnum = (StringComparison?)nullableInt;
1) Sim, o tipo de enum subjacente é int e é por isso que funciona dessa maneira. Ainda mais. Você pode fazer o seguinte:
enum MyEnum { One = 1, Two = 2, } int i = 3; MyEnum myEnum = (MyEnum)i; // This works without exceptions.
2) porque StringComparison?
é na verdade Nullable<StringComparison>
que é tipo diferente. E as
O operador verifica apenas se o objeto é do mesmo tipo especificado no operador.