C# Enum to Int: Cast, Convert, and Underlying Types
c# enum to int: Learn how to convert C# enums to their integer values using casts, Convert, and understand underlying types and common pitfalls.
Converting a C# enum to int is a common operation when you need to store, transmit, or compare enum values numerically. The most direct way is an explicit cast, but there are nuances around the underlying type and invalid values that can affect correctness.
The Explicit Cast Is the Default Approach
In C#, an enum is a value type that has an underlying integral type. By default, that type is int. The simplest way to convert an enum value to its integer representation is an explicit cast:
enum Color { Red, Green, Blue } Color color = Color.Green; int value = (int)color; Console.WriteLine(value); // Output: 1
The cast is compile-time and does not involve any runtime conversion logic. It simply reinterprets the enum's underlying storage as an integer. This is the recommended approach for most scenarios because it is direct, readable, and has no overhead.
The cast works regardless of the underlying type. If the enum is declared with a different underlying type, such as byte or long, the cast still produces the correct integer value, but you must ensure the target type can hold it. For example:
enum ByteEnum : byte { A = 0, B = 1 } byte b = (byte)ByteEnum.B;
Here the cast to byte is safe because the underlying type is already byte. Casting to int would also work, but the value would be widened.
Using Convert.ToInt32 for Enum to Int
The Convert class provides a more general conversion method that works with any object implementing IConvertible. Since enums implement IConvertible, you can use Convert.ToInt32:
int value = Convert.ToInt32(Color.Blue);
This approach is useful when you are working with a value that is typed as object or when you need to handle conversions from multiple types in a uniform way. However, it comes with a cost: the enum value is boxed to an object before the conversion, which allocates memory. For a one-off conversion this is negligible, but in a hot loop it may be worth avoiding.
Convert.ToInt32 also respects the underlying type. If the enum's underlying type is long, the conversion still produces an int, but it may throw an OverflowException if the value exceeds the range of int. The explicit cast, by contrast, would simply truncate or wrap, depending on the context.
Understanding the Underlying Type
Every enum has an underlying type that can be specified at declaration. The default is int, but you can use byte, sbyte, short, ushort, uint, long, or ulong. The underlying type determines the storage size and the range of valid values.
enum Status : byte { Inactive = 0, Active = 1 }
When converting to int, the value is widened from byte to int without issue. However, if the underlying type is ulong and the value is larger than int.MaxValue, an explicit cast to int will produce a value that is not meaningful because of overflow. In such cases, you should cast to the appropriate larger type, such as long or ulong, or use Convert.ToUInt64 if you need the exact value.
The underlying type also affects how the enum participates in arithmetic and bitwise operations. For example, incrementing an enum with a byte underlying type may cause overflow if the value exceeds 255. This is a separate concern, but it influences how you choose the underlying type for your enum.
Handling Invalid Enum Values
An enum variable can hold any value that fits its underlying type, even if that value is not defined in the enum declaration. This can happen when the value comes from an external source, such as deserialization or a database. When you convert such a value to an integer, you get the raw number, which may not correspond to any named constant.
enum Color { Red = 0, Green = 1, Blue = 2 } Color unknown = (Color)5; int value = (int)unknown; // 5
This is often the source of bugs if you assume the enum only contains defined values. If you need to validate that an integer is a valid enum value, use Enum.IsDefined before conversion or before casting the integer back to the enum. However, Enum.IsDefined has performance implications because it uses reflection, so it should be used judiciously.
Performance and Allocation Considerations
The explicit cast from enum to int is a no-op at runtime; it simply reinterprets the bits. There is no boxing, no method call, and no allocation. This makes it the most efficient option for performance-sensitive code.
Convert.ToInt32, on the other hand, boxes the enum value because it accepts an object. The boxing allocation occurs even if the enum is already an int underneath. In tight loops or in code that processes a large number of enum values, this can add measurable overhead. If you are writing a library or a hot path, prefer the explicit cast.
Another consideration is the use of Enum.Parse or Enum.TryParse for the reverse direction (string to enum). Those methods also involve reflection and are slower than a direct cast. For enum-to-int, the explicit cast is the clear winner.
Practical Usage Patterns
A common use case is storing an enum value in a database column that is an integer. You would convert the enum to an int before saving, and then convert back when reading. The explicit cast is straightforward:
int dbValue = (int)order.Status;
Another pattern is using an enum as a dictionary key or in a switch statement. While you can switch directly on the enum, you might need the integer value for logging or comparison with external systems.
int statusCode = (int)response.Status;
When you need to iterate over all values of an enum, you can use Enum.GetValues, but that returns an array of the enum type. Converting each element to int can be done with a cast in a loop.
Common Pitfalls and Edge Cases
One subtle pitfall is relying on the default values of an enum. If you do not explicitly assign values, the first member is 0, and subsequent members increment by 1. If you change the order or insert a new member, the integer values shift, which can break persisted data or external contracts. Always assign explicit values if the enum represents a stable contract.
Another edge case is an enum with a flag attribute. Flags enums are used for bitwise combinations, and converting to int is still valid, but you must ensure the integer representation is meaningful. For example, [Flags] enum Permissions { None = 0, Read = 1, Write = 2, Execute = 4 }. Converting a combination like Read | Write to int yields 3. This is expected, but you should be careful when comparing such values.
Finally, consider the Enum base class methods. Enum.GetName and Enum.GetNames work with the enum type and return strings, not integers. If you need the integer value for a given name, you can use Enum.Parse and then cast, but that is a roundabout way. The direct cast is always available.