Consider the following::
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 things::
StringComparison
? I guess this is because it's underlying type is Int32
but I still find it odd.nullableEnum
have a value of null?As I understand the only valid unboxing is from a boxed value type is to it's type or to a nullable type. If int
can unbox to Enum
, then why doesn't the same hold true for the nullable values? Similarly, if Instead of 5 I boxed StringComparison.OrdinalIgnoreCase
, it would be that nullableInt
would be null, but nullableEnum
would not be.
Strictly speaking I think it's a bug in implementation detail of the runtime, since the C# spec says
Unboxing to a nullable-type produces the null value of the nullable-type if the source operand is null, or the wrapped result of unboxing the object instance to the underlying type of the nullable-type otherwise.
That is, if unboxing to StringComparison works, then unboxing to Nullable<StringComparison> should work too. It's a little unclear whether both should work or both should fail. The spec says that
For an unboxing conversion to a given non-nullable-value-type to succeed at run-time, the value of the source operand must be a reference to a boxed value of that non-nullable-value-type.
You have to decide whether a boxed int is a considered to be a boxed value of type StringComparison because the underlying type of StringComparison is int. The spec goes on to say that an InvalidCastException is thrown if the box contains an "incompatible object". An int is certainly "compatible" with StringComparison, because you can safely copy the four bytes from the heap into your StringComparison variable.
When you cast enum or integer to object, it still holds type information. So box is StringComparison
will return false
. But it is allowed to cast any enum or int to any enum, so explicit cast (StringComparison)box
works. It is a special case for enums. Nullable<T>
, on the other hand, is just a usual class, T is not handled in any specific way when you cast or check type. This is why this code will throw exception.
StringComparison? nullableEnum = (StringComparison?)nullableInt;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With