Why enums require an explicit cast to int type?

13,653

Solution 1

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.

Solution 2

Because enums do not have to be int based:

The enum keyword is used to declare an enumeration, a distinct type consisting of a set of named constants called the enumerator list. Every enumeration type has an underlying type, which can be any integral type except char.

So you can do something like this:

enum Something :long  { valueX = 0, valueY = 2147483648L }

Solution 3

Why do you say no data loss? Not all enums are ints, after all. They must be integer-typed, but that can mean byte, ulong, etc.

As a corner-case the literal 0 is implicit, but; what would be your use-case here?

It is pretty rare I need to do this - usually data import etc. An occasional no-op cast makes perfect sense to me, and avoids accidental mistakes.

Solution 4

I think that the answer to "Why enums require an explicit cast to int type?" is that strongly-typed enums as per C# are a useful defence against common programming errors.

Imagine I had a painting management application, based on two enums:

enum Textures { Gloss, Satin, Matt };
enum Colors { White, Green, Red, Blue, Brown };

And a room-painting method like this:

private void PaintRoom (Textures texture, Colors color)

In a language with strong enum typing like in C#, a command like this:

 // nonsensical attempt to have texture=White and color=Matt
PaintRoom(Colors.White, Textures.Matt);

...would yeild a compile-time error (can't put color into where a texture is expected and vice versa). But in languages where the enums aren't strongly-typed and/or implicit conversion can occur (including C and C++), both our Colors and our Textures can be treated as int, so we can happily issue a PaintRoom(Colors.White, Textures.Matt) command and it will compile fine, but we end up with a room painted Gloss Red (0, 2) instead of the Matt White (2, 0) that we intended and the code on a quick glance seems to say.

So strongly-typed enums are mostly a good thing, to stop people accidentally putting enums into places they were not meant for. And where someone really wants their enum as an int, C# forces the coder to make their intention clear by insisting on an explicit conversion.

Solution 5

Would it not be more intuitive if it was implicit, say when you have a higher level method like:

I actually think not. In this case, you're trying to use an Enum in an edge case.

However, if enums were implicitly converted to integer values, this would dramatically reduce their effectiveness. By forcing an int conversion explicitly, the compiler is treating enum as a special type - one of many options, not as an integer. This more clearly demonstrates the intent of the enum, and reduces the chance of programmer mistakes (ie: assigning values that aren't defined in the enum to an enum variable, etc).

I personally am glad that enum in C# is more than (effectively) a constant int value.

Share:
13,653
Joan Venge
Author by

Joan Venge

Professional hitman.

Updated on June 22, 2022

Comments

  • Joan Venge
    Joan Venge almost 2 years

    There is no data loss by doing this, so what's the reason for having to explicitly cast enums to ints?

    Would it not be more intuitive if it was implicit, say when you have a higher level method like:

    PerformOperation ( OperationType.Silent type )
    

    where PerformOperation calls a wrapped C++ method that's exposed as such:

    _unmanaged_perform_operation ( int operation_type )