Enums
Replace magic numbers and strings with named constants the compiler can check.
9 min read
You will learn
- Declare an enum and use its values
- Switch over enum values
- Convert between enums, strings and numbers
- Combine options with [Flags] enums
Magic values are fragile
How would you store an order's status? A string like "shipped" invites typos ("shiped") that nobody catches until production. A number like 2 means nothing to the next reader. An enum gives a fixed set of named values that the compiler checks:
enum OrderStatus
{
Pending,
Paid,
Shipped,
Delivered,
Cancelled,
}
var status = OrderStatus.Paid;
if (status == OrderStatus.Shipped) { ... }
status = OrderStatus.Shiped; // ❌ compile error — typo caught immediatelyEnum types and their members use PascalCase. Enums are value types.
Enums are numbers underneath
Each member has an integer value, starting at 0 by default. You can set them explicitly:
enum HttpStatus
{
Ok = 200,
NotFound = 404,
ServerError = 500,
}
int code = (int)HttpStatus.NotFound; // 404
var status = (HttpStatus)200; // HttpStatus.OkWatch out
Casting any integer to an enum compiles — (OrderStatus)99 is allowed, even though there's no such member. Validate numbers from outside with Enum.IsDefined.
Enums and switch
Enums pair naturally with switch expressions:
string Describe(OrderStatus s) => s switch
{
OrderStatus.Pending => "Waiting for payment",
OrderStatus.Paid => "Preparing your order",
OrderStatus.Shipped => "On its way",
OrderStatus.Delivered => "Delivered",
OrderStatus.Cancelled => "Cancelled",
_ => throw new ArgumentOutOfRangeException(nameof(s)),
};Converting to and from strings
Console.WriteLine(OrderStatus.Shipped); // "Shipped" — ToString gives the name
if (Enum.TryParse<OrderStatus>("delivered", ignoreCase: true, out var parsed))
Console.WriteLine(parsed); // Delivered
foreach (var s in Enum.GetValues<OrderStatus>()) // every member
Console.WriteLine($"{(int)s}: {s}");[Flags]: combining options
Some settings aren't "one of", but "any combination of": file permissions, days of the week a shop is open, text styles. A flags enum gives each option its own bit:
[Flags]
enum Days
{
None = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64,
Weekend = Saturday | Sunday,
}
var open = Days.Monday | Days.Wednesday | Days.Saturday; // combine with |
Console.WriteLine(open); // Monday, Wednesday, Saturday
Console.WriteLine(open.HasFlag(Days.Wednesday)); // True
Console.WriteLine((open & Days.Weekend) != 0); // True — open on at least one weekend day
open &= ~Days.Monday; // remove a flagTry it
C# runtime not loaded
Key takeaways
- Enums are named sets of constants — checked by the compiler, readable in code.
- Each member has an integer value (from 0 by default); cast to convert.
ToString()andEnum.TryParseconvert to and from names.[Flags]enums with power-of-two values can be combined with|and checked withHasFlag.
Exercise
Implement Next (Red → Green → Yellow → Red) and DurationSeconds (Red 30, Green 25, Yellow 5) for the traffic light. Then implement CanEdit, which is true only when the permissions include both Read and Write.
C# runtime not loaded
Hint 1
Switch expressions are perfect here: light switch { TrafficLight.Red => TrafficLight.Green, ... }.
Hint 2
HasFlag checks for one or more flags: permissions.HasFlag(Permission.Read | Permission.Write).
Show solution
var light = TrafficLight.Red;
for (int i = 0; i < 4; i++)
{
Console.WriteLine($"{light} for {DurationSeconds(light)}s");
light = Next(light);
}
TrafficLight Next(TrafficLight light) => light switch
{
TrafficLight.Red => TrafficLight.Green,
TrafficLight.Green => TrafficLight.Yellow,
_ => TrafficLight.Red,
};
int DurationSeconds(TrafficLight light) => light switch
{
TrafficLight.Red => 30,
TrafficLight.Green => 25,
TrafficLight.Yellow => 5,
_ => throw new ArgumentOutOfRangeException(nameof(light)),
};
bool CanEdit(Permission permissions) =>
permissions.HasFlag(Permission.Read | Permission.Write);
enum TrafficLight { Red, Yellow, Green }
[Flags]
enum Permission
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
}Quiz
4 questions · 3 correct to pass1.Given `enum Size { Small, Medium, Large }`, what is `(int)Size.Large`?
2.What does `Size.Medium.ToString()` return?
3.Why do [Flags] enums use values 1, 2, 4, 8…?
4.What's the safest way to turn user text like "Large" into a Size?
To complete this lesson
- ○ Solve the exercise
- ○ Pass the quiz (3/4 correct)