Boxed nullable underlying type can be cast to enum but boxed enum type can't be cast to nullable type

nawfal
  • Boxed nullable underlying type can be cast to enum but boxed enum type can't be cast to nullable type.

And similarly,

  • Boxed nullable enum can be cast to underlying type but boxed underlying type can't be cast to nullable enum.

Ok, I know "boxed nullable type" is not the best way to describe it, but it's for the sake of the question. I'm aware it's the underlying value type that's getting boxed.

I will show it with examples. Assume I have an enum with int as the underlying type.

enum Sex { Male, Female }

Case I:

int? i = 1;
object o = i;
Sex e = (Sex)o; //success

//but

Sex e = Sex.Male;
object o = e;
int? i = (int?)o; //invalid cast

Case II:

Sex? e = Sex.Male;
object o = e;
int i = (int)o; //success

//but

int i = 1;
object o = i;
Sex? e = (Sex?)o; //invalid cast

In a nutshell,

(enum)int? -> succeeds
(int?)enum -> the reverse fails

(int)enum? -> succeeds
(enum?)int -> the reverse fails

Or in even simpler terms,

cast to non-nullable -> succeeds
cast to nullable -> fails

Now I do know that once you box a value type, it can be cast back only to the original type. But since by C# rules, a boxed int can be cast to enum and a boxed enum can be cast to int, and a boxed int to int? and a boxed int? to int, I was looking for a consistent understanding of other scenarios as well, ie the ones listed above. But I dont get the logic. For one, I feel if they all failed or if they all succeeded, it made more sense to developers. Two, even the successful casts look a little odd. I mean since a value type can be implicitly cast to its nullable equivalent (and not the other way around), a cast to nullable should anyway succeed, but with the current implementation a nullable type is being successfully cast to non-nullable which can even fail if the former had a null value. Had this whole thing been other way around, it would have been easier comprehending. An example like:

Sex? e = null;
object o = e;
int i = (int)o; //succeeds, but sure to explode on cast

//but

int i = 1;
object o = i;
Sex? e = (Sex?)o; //invalid cast, even though its always a safe cast

Questions:

  1. So what C# rule is letting this happen?

  2. Is there a simple way I can remember this?

Jon Skeet

I think this is a subtlety of the unbox and unbox.any IL instructions.

From ECMA 335, section III.4.32 (unbox operation - unbox.any is similar)

Exceptions:
System.InvalidCastException is thrown if obj is not a boxed value type, valuetype is a Nullable<T> and obj is not a boxed T, or if the type of the value contained in obj is not verifier-assignable-to (III.1.8.2.3) valuetype.

So for example, in this case:

Sex e = Sex.Male;
object o = e;
int? i = (int?)o;

it fails entirely correctly - because valuetype is Nullable<int> and the value of obj is not a boxed int. The "verifier-assignable-to" part doesn't apply for the Nullable<T> case.

I doubt that any of this behaviour is described in the C# specification, unfortunately - I don't think the unboxing behaviour from "boxed int" to "enum with an underlying type of int" is described, as far as I can see, which is a sort of prerequisite to then including nullability in the mix.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Why can't C++11 strongly-typed enum be cast to underlying type via pointer?

From Dev

Why can't I have an enum as the underlying type of another enum?

From Dev

How to cast an int into a nullable type?

From Dev

How to cast an int into a nullable type?

From Dev

Java cannot cast from boxed type to primitive type

From Dev

Why is enum cast on short possible but not boxed generic enum cast?

From Dev

Cast to value type 'Enum' failed as the materialized value is null. Either the result type's param or query must use nullable type

From Dev

Is it safe to reinterpret_cast an enum class variable to a reference of the underlying type?

From Dev

Swift integer type cast to enum

From Dev

How one can cast ref to enum value as u16 (base enum type) in Rust?

From Dev

Is there a way to down cast an enum rawValue to its type?

From Dev

Type cast failed in switch for enum with restricted storage

From Java

Can sizeof(enum) differ from sizeof(std::underlying_type<Enum>::type)?

From Dev

Can't cast value of type UIViewController to PatternDetailViewController

From Dev

Why can't I cast `this` to a generic type?

From Dev

Can't cast gson to my Object type

From Dev

static_cast to enum class from underlying type value and switch for compiler assistance

From Dev

static_cast to enum class from underlying type value and switch for compiler assistance

From Dev

PowerShell can't use the matching enum type?

From Dev

Method that accepts a "generic" Enum as a parameter, then cast to a diff enum type at runtime

From Dev

Create an array of Nullable objects with different underlying type?

From Dev

enum underlying type vs normal type

From Dev

How to cast a C# nullable Enum to int in c++/CLI

From Dev

How to cast java.lang.reflect.Type to enum?

From Dev

Postgres: Default for column (string) cannot be cast automatically to type enum

From Dev

How to cast java.lang.reflect.Type to enum?

From Dev

Cannot cast DBNull.Value to type 'System.DateTime'. Please use a nullable type

From Dev

Cannot cast DBNull.Value to type 'System.DateTime'. Please use a nullable type

From Dev

The specified cast from a materialized 'System.Byte[]' type to a nullable 'System.Byte' type is not valid

Related Related

  1. 1

    Why can't C++11 strongly-typed enum be cast to underlying type via pointer?

  2. 2

    Why can't I have an enum as the underlying type of another enum?

  3. 3

    How to cast an int into a nullable type?

  4. 4

    How to cast an int into a nullable type?

  5. 5

    Java cannot cast from boxed type to primitive type

  6. 6

    Why is enum cast on short possible but not boxed generic enum cast?

  7. 7

    Cast to value type 'Enum' failed as the materialized value is null. Either the result type's param or query must use nullable type

  8. 8

    Is it safe to reinterpret_cast an enum class variable to a reference of the underlying type?

  9. 9

    Swift integer type cast to enum

  10. 10

    How one can cast ref to enum value as u16 (base enum type) in Rust?

  11. 11

    Is there a way to down cast an enum rawValue to its type?

  12. 12

    Type cast failed in switch for enum with restricted storage

  13. 13

    Can sizeof(enum) differ from sizeof(std::underlying_type<Enum>::type)?

  14. 14

    Can't cast value of type UIViewController to PatternDetailViewController

  15. 15

    Why can't I cast `this` to a generic type?

  16. 16

    Can't cast gson to my Object type

  17. 17

    static_cast to enum class from underlying type value and switch for compiler assistance

  18. 18

    static_cast to enum class from underlying type value and switch for compiler assistance

  19. 19

    PowerShell can't use the matching enum type?

  20. 20

    Method that accepts a "generic" Enum as a parameter, then cast to a diff enum type at runtime

  21. 21

    Create an array of Nullable objects with different underlying type?

  22. 22

    enum underlying type vs normal type

  23. 23

    How to cast a C# nullable Enum to int in c++/CLI

  24. 24

    How to cast java.lang.reflect.Type to enum?

  25. 25

    Postgres: Default for column (string) cannot be cast automatically to type enum

  26. 26

    How to cast java.lang.reflect.Type to enum?

  27. 27

    Cannot cast DBNull.Value to type 'System.DateTime'. Please use a nullable type

  28. 28

    Cannot cast DBNull.Value to type 'System.DateTime'. Please use a nullable type

  29. 29

    The specified cast from a materialized 'System.Byte[]' type to a nullable 'System.Byte' type is not valid

HotTag

Archive