Skip to content

C# - Enums

An enumeration, or enum, is a value type that defines a set of named constants. Enums make your code more readable and maintainable by allowing you to use descriptive names instead of ‘magic numbers’ or strings.

Use an enum when you have a distinct set of related values, such as days of the week, states in a state machine (e.g., Pending, Processing, Completed), or user roles (Admin, Member, Guest).

You declare an enum using the enum keyword. By default, the underlying type of an enum is int, and the first member has a value of 0, with each subsequent member incrementing by 1.

public enum DayOfWeek
{
Sunday, // 0
Monday, // 1
Tuesday, // 2
Wednesday, // 3
Thursday, // 4
Friday, // 5
Saturday // 6
}

You can declare a variable of the enum type and assign one of its members to it. This provides strong type safety.

// Using top-level statements (modern C#)
DayOfWeek today = DayOfWeek.Wednesday;
Console.WriteLine($"Today is {today}.");
// To get the integer value, you must cast it explicitly.
int dayValue = (int)today;
Console.WriteLine($"Numeric value for {today} is {dayValue}.");
public enum DayOfWeek
{
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}

When the above code is executed, it produces the following result:

Today is Wednesday.
Numeric value for Wednesday is 3.

You can customize the integer values of enum members. You can also change the underlying type to any integral type except char, such as byte or long, for performance or storage optimization.

// Using a 'byte' for efficiency and specifying custom values
public enum HttpStatus : byte
{
OK = 200,
NotFound = 44, // Values don't have to be contiguous
InternalServerError = 50
}
HttpStatus status = HttpStatus.OK;
Console.WriteLine($"Status: {status} (Value: {(byte)status})");

Enums are perfect for switch logic. Modern C# introduced switch expressions, which offer a more concise and readable syntax than traditional switch statements.

DayOfWeek today = DayOfWeek.Friday;
string message = today switch
{
DayOfWeek.Saturday or DayOfWeek.Sunday => "It's the weekend!",
DayOfWeek.Friday => "It's almost the weekend!",
_ => "It's a weekday."
};
Console.WriteLine(message);
// This will output: It's almost the weekend!

By adding the [Flags] attribute and assigning powers of two as values, you can combine enum members using bitwise operators. This is useful for representing a set of options or permissions.

[Flags]
public enum Permissions
{
None = 0, // 0000
Read = 1, // 0001
Write = 2, // 0010
Execute = 4, // 0100
All = Read | Write | Execute
}
// Assign multiple permissions using the bitwise OR operator
Permissions userPermissions = Permissions.Read | Permissions.Write;
Console.WriteLine($"User permissions: {userPermissions}");
// Check for a specific permission using HasFlag()
bool canWrite = userPermissions.HasFlag(Permissions.Write);
Console.WriteLine($"User has Write permission? {canWrite}"); // True
bool canExecute = userPermissions.HasFlag(Permissions.Execute);
Console.WriteLine($"User has Execute permission? {canExecute}"); // False

It’s common to convert strings or integers into enum values, for example, when reading from a configuration file or a database. Using Enum.TryParse is the safest way to do this, as it prevents exceptions from invalid input.

// Safely parsing a string to an enum
string statusInput = "Completed";
if (Enum.TryParse<OrderStatus>(statusInput, out OrderStatus status))
{
Console.WriteLine($"Successfully parsed string: {status}");
}
else
{
Console.WriteLine($"'{statusInput}' is not a valid order status.");
}
// Converting an integer to an enum
int statusCode = 2;
OrderStatus statusFromInt = (OrderStatus)statusCode;
Console.WriteLine($"Converted from integer: {statusFromInt}");
public enum OrderStatus { Pending, Processing, Shipped, Completed }
  • Mistake: Casting an undefined integer to an enum. This will not throw an error but can lead to invalid states. Enum.IsDefined can be used to check validity before casting.
  • Best Practice: Use singular names for enums (e.g., OrderStatus, not OrderStatuses) because a variable of that type holds a single value.
  • Best Practice: Use Enum.TryParse instead of Enum.Parse to gracefully handle invalid string inputs without a try-catch block.