Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need to type cast an enum in C#

Tags:

c#

I have an enum like:

public enum Test:int
{
   A=1, 
   B=2
}

So here I know my enum is an int type but if I want to do something like following:

int a = Test.A;

this doesn't work.

If I have a class like:

public class MyTest
{
    public static int A =1;
}

I can say ,

int a = MyTest.A;

Here I don't need to cast A to int explicitly.

like image 932
Embedd_0913 Avatar asked Aug 15 '12 11:08

Embedd_0913


3 Answers

So here I know my enum is an int type

No, it's not. It has an underlying type of int, but it's a separate type. Heck, that's half the point of having enums in the first place - that you can keep the types separate.

When you want to convert between an enum value and its numeric equivalent, you cast - it's not that painful, and it keeps your code cleaner in terms of type safety. Basically it's one of those things where the rarity of it being the right thing to do makes it appropriate to make it explicit.

EDIT: One oddity that you should be aware of is that there is an implicit conversion from the constant value 0 to the enum type:

Test foo = 0;

In fact, in the MS implementation, it can be any kind of constant 0:

Test surprise = 0.0;

That's a bug, but one which it's too late to fix :)

I believe the rest for this implicit conversion was to make it simpler to check whether any bits are set in a flags enum, and other comparisons which would use "the 0 value". Personally I'm not a fan of that decision, but it's worth at least being aware of it.

like image 85
Jon Skeet Avatar answered Nov 08 '22 20:11

Jon Skeet


"The underlying type specifies how much storage is allocated for each enumerator. However, an explicit cast is needed to convert from enum type to an integral type".

like image 38
Science_Fiction Avatar answered Nov 08 '22 20:11

Science_Fiction


With your updated example:

public class MyTest
{
    public static int A =1;
}

And usage:

int a = MyTest.A;

That's not how enums look. Enums look more like (comments are places where we differ from a real enum):

public struct MyTest /* Of course, this isn't correct, because we'll inherit from System.ValueType. An enum should inherit from System.Enum */
{
    private int _value; /* Should be marked to be treated specially */
    private MyTest(int value) /* Doesn't need to exist, since there's some CLR fiddling */
    {
       _value = value;
    }

    public static explicit operator int(MyTest value) /* CLR provides conversions automatically */
    {
       return value._value;
    }
    public static explicit operator MyTest(int value) /* CLR provides conversions automatically */
    {
       return new MyTest(value);
    }

    public static readonly MyTest A = new MyTest(1); /* Should be const, not readonly, but we can't do a const of a custom type in C#. Also, is magically implicitly converted without calling a constructor */

    public static readonly MyTest B = new MyTest(2); /* Ditto */
}

Yes, you can easily get to the "underlying" int value, but the values of A and B are still strongly typed as being of type MyTest. This makes sure you don't accidentally use them in places where they're not appropriate.

like image 3
Damien_The_Unbeliever Avatar answered Nov 08 '22 19:11

Damien_The_Unbeliever