Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting as Nullable<T> causes an InvalidCastException to be thrown [duplicate]

I have an enum, Foo:

public enum Foo { Alpha, Bravo, Charlie }

If I attempt the following cast from a boxed int to a Foo?, I get an InvalidCastException:

var x = (Foo?)(object)1;

This led me to some experimentation...

var x = (Foo)(object)1; // succeeds
var x = (long)(object)1; // fails
var x = (long?)(object)1; // fails
var x = (long)1; // succeeds
var x = (long?)1; // succeeds
var x = (int)(object)1; // succeeds
var x = (int?)(object)1; // succeeds

What this tells me is that you can cast from a boxed int to an enum but not to a long, and you cannot convert from a boxed int to any kind of nullable except an int?.

By the way, the reason I'm casting the int to object first is that I'm really trying to cast from an int to a generic parameter TValue, like this:

var x = (TValue)(object)1;

If I didn't have (object), it wouldn't compile. (See this blog post by Eric Lippert for details.)

Questions

  1. Why can you convert from a boxed int to an enum, but not to a nullable enum (and not to a long nor a long?)?

  2. What's the easiest way to rewrite var x = (TValue)(object)1; so that it compiles, works at runtime, and is performant (assuming TValue is determined to be a Foo? at runtime)?

like image 525
devuxer Avatar asked Sep 05 '12 23:09

devuxer


2 Answers

To answer the first question, you can convert from a boxed value to an enum only if the boxed value is of the enum's underlying type. Had you declared

enum Foo : byte { ...

you would not be able to cast from boxed int to Foo.

To answer the second question, try

var x = (TValue)Enum.ToObject(typeof(TValue), 1);

This involves boxing, though; if you need a solution that won't box, it will be more complicated.

like image 96
phoog Avatar answered Sep 21 '22 02:09

phoog


Nullables are not some special category of atomic types, but shorthand for type Nullable<T>, which is why you can't cast a boxed int to a nullable enum. If you want to create a nullable enum, you can do it thusly:

var x = new Nullable<Foo>((Foo)1);

This answers both your questions, I think!

like image 23
Ethan Brown Avatar answered Sep 20 '22 02:09

Ethan Brown