Nullable Enum

V

Vikas Manghani

Hi
I have an Enum say
publlic enum TestEnum
{
Val1 = 1,
Val2 = 2
}

In another class that uses a field of this Enum

public class TestClass
{
.....
public Nullable<TestEnum> enumValue;
]


In the client code, I want to assign this field a value from a generic
System.Object reference.
So

public class Client
{
public static void Main(String[] args)
{
object o = 2;
TestClass c1 = new TestClass();
c1.enumValue = (Nullable<TestEnum>)o;

//The above statement fails. But the following succeeds.
c1.enumValue = (TestEnum)o;

//Similarly

object o = null;
TestClass c2 = new TestClass();
c2.enumValue = (Nullable<TestEnum>)o;

//The above statement succeeds. But the following fails.
c3.enumValue = (TestEnum)o;
}
}
So basically, I have to test against null always before assigning a value.
Is there a way to achieve the type cast with a single statement?

Thanks in advance
Vikas
 
P

Pavel Minaev

First of all, just a reminder that C# allows to write nullable types
shorter: instead of "Nullable<T>", you can simply write "T?". I'll use
the latter form throughout my reply for the sake of brevity.

                object o = 2;
                TestClass c1 = new TestClass();
                c1.enumValue = (Nullable<TestEnum>)o;

                //The above statement fails. But the following succeeds.
                c1.enumValue = (TestEnum)o;

Actually, according to C# language specification, the second cast
should also fail. This is because it is an unboxing conversion, and
unboxing is supposed to only be valid for the _precise_ type of boxed
value - i.e. you cannot unbox float to int, or uint to int, or int to
enum. Your case falls under the last point - you have a boxed plain
int, and are trying to unbox it to a different type, enum.

Now, Microsoft implementation of the spec - .NET - is actually more
relaxed, and gives some leeway - you can unbox int to uint and vice
versa, and you can also unbox int to enum and vice versa. However,
this is an undocumented extension, and it would be unwise to rely upon
that; the fact that it does not extend to nullable types is further
testament to that.
                //Similarly

                object o = null;
                TestClass c2 = new TestClass();
                c2.enumValue = (Nullable<TestEnum>)o;

                //The above statement succeeds. But the following fails.
                c3.enumValue = (TestEnum)o;

This is more obvious. Any enum type is a value type. Value types do
not have the concept of a null value. So, when unboxing null to a
value type, the only meaningful thing to do is to throw an exception.
It would be precisely the same for (int)(object)null, for example.
So basically, I have to test against null always before assigning a value..
Is there a way to achieve the type cast with a single statement?

In a single _statement_, yes, since you can chain casts. The correct
form for first one would be:

c1.enumValue = (TestEnum?)(TestEnum)(int)o;

Note that we first unbox o to its actual type, which is int, and only
then do cast to enum. I'm not sure whether you need (TestEnum) there
or not - it may well be that it is possible to cast an int directly to
a nullable enum type. Try both with and without, and see what works
for you. Also note that in this specific case of assignment, the final
cast to (TestEnum?) wouldn't be needed anyway, as there's always an
implicit conversion from T to T? for any type T.

In the second case, there is no definite answer, as it depends on what
you want to do with null. A fairly typical case is substituting some
default value; in this case, you'd want to operator ?? - null
coalescing:

c3.enumValue = (TestEnum?)o ?? TestEnum.SomeDefaultValue;
 
V

vikas.manghani

Hi Pavel
Thanks a million for the comprehensive reply. It really clears a lot
of things.
The problem that I have on my hands is that the data to be assigned
to the Enum variable is read from the database.
Hence it could be an Int Or null. This value should be assigned to a
Nullable Enum Property of a Data Entity.
Hence I would still need to check everytime if the data received from
the DataReader is null or not.
Would that be right??

Thanks in advance
Vikas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top