Why Enums Require an Explicit Cast to Int Type

Why enums require an explicit cast to int type?

There are two primary and inconsistent uses of enums:

enum Medals
{ Gold, Silver, Bronze }

[Flags]
enum FilePermissionFlags
{
CanRead = 0x01,
CanWrite = 0x02,
CanDelete = 0x04
}

In the first case, it makes no sense to treat these things as numbers. The fact that they are stored as integers is an implementation detail. You can't logically add, subtract, multiply or divide Gold, Silver and Bronze.

In the second case, it also makes no sense to treat these things as numbers. You can't add, subtract, multiply or divide them. The only sensible operations are bitwise operations.

Enums are lousy numbers, so you should not be able to treat them as numbers accidentally.

Why must I use an explicit cast when using an enum in place of its underlying type?

Very simply because C# is strongly typed. An enum value is not of type byte even if you set it's translated values as byte, so you must cast it as byte before you can use it with a function that is expecting type byte. It's no different than casting another type.

Also, if your focus is on keeping things clean, you could consider rewriting (or overloading) your method slightly so that the cast is invisible to everything outside of it. It doesn't change the solution, but assuming you will be reusing the method in more than one place, it is less code:

public void AppendAsHex(StringBuilder sb, Foo b)
{
AppendAsHex(sb, (byte)b);
}
public void AppendAsHex(StringBuilder sb, byte b)
{
sb.AppendFormat("{0:X}", b);
}

At which point, this would work

Foo theDerp = Foo.DERP;
AppendAsHex(sb, theDerp);

Why do I have to explicitly cast an enum that I have specified the underlying type for?

This is a type safety feature. Implicit conversions have a long history of associated issues in C++, have a look at Stephen Dewhurst's book "C++ Gotchas" - the longest chapter is that on conversions.

Recall that an enumeration is nothing but a way to bind a constant value to a comprehensible name. This way, there is a finite, documented set of possible values, and by an implicit conversion, you massively extend the domain without giving any notice. Example:

void f(uint16_t arg); // arg can have 65536 different values

enum class Apples : uint16_t { GRANNY_SMITH = 1 }; // one possible value

If this compiles:

f(Apples::GRANNY_SMITH);

you have just given up the restrictiveness without giving notice. Instead,

f(static_cast<uint16_t>(Apples::GRANNY_SMITH));

is clearer and uglier. The clumsy nature of the cast tells you "why do you even do it?", and answering this question shouldn't be too easy. You created the enumeration to refer to possible values by typing out their associated names, right?

c# : Why is a cast needed from an Enum to an INT when used in a switch statement?, enums are ints

In C# enums aren't just numbers. Rather, they are numbers associated with the type or number with a name in a context.

To avoid casts in case statements, you can do a cast in switch:

switch((ViewBy)Convert.ToInt32(uxView.SelectedValue))

This, however, has its own problems. For example, this piece of code will write out 7 to the console.

enum ViewBy
{
ChuckNorris = 1,
JamesBond
}

Console.WriteLine((ViewBy)7);

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

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.

Type-casting enum to integer and vice versa

enum to int is unambiguous cast (assuming C++ 03 where enum is basically an int), will be performed implicitly no problem. int to enum is potentially errorneous as it's a narrowing cast, not every int value is a valid enum value. That's why casting int to enum is only possible explicitly.

Same holds for C++ 11 and later standards, with the exception that C++ 11 introduced strongly typed enums and specific size enums.

Strongly typed enum is declared enum class instead of just enum, and it cannot be converted to an integer nor any other type, save for a user-defined conversion operator or function, or brute force (static_cast). Sized enums are declared like this: enum Colors : char {...}. This particular enum's values will have char type instead of the default int.



Related Topics



Leave a reply



Submit