Enums in .NET
Enumerations, or enums, are a special data type that enables for a variable to be a set of named constants. They provide a way to define a type that has a fixed set of possible values. This makes code more readable and less prone to errors compared to using raw integer constants.
What is an Enum?
An enum defines a set of named integral constants. Each constant in the enum is assigned a specific underlying integral value. By default, the first enumerator is assigned the value 0, and subsequent enumerators are assigned incrementing integral values. However, you can explicitly assign values to any or all enumerators.
Declaring an Enum
You declare an enum using the enum keyword, followed by the enum's name and then a comma-separated list of its members enclosed in curly braces.
public enum DayOfWeek
{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
Underlying Type
By default, the underlying type of an enum is int. You can specify a different integral type (like byte, short, long, sbyte, ushort, uint, or ulong) by appending a colon and the type name after the enum name:
public enum Status : byte
{
Pending = 0,
Processing = 1,
Completed = 2,
Failed = 3
}
Using Enums
Once declared, you can use an enum type just like any other data type. You can declare variables of the enum type and assign them values from the enum members.
DayOfWeek today = DayOfWeek.Wednesday;
Status currentStatus = Status.Processing;
Console.WriteLine($"Today is: {today}"); // Output: Today is: Wednesday
Console.WriteLine($"Current status code: {(int)currentStatus}"); // Output: Current status code: 1
Accessing Enum Members
You can access enum members using the enum name followed by a dot and the member name, e.g., DayOfWeek.Friday.
Casting to and from Enum Types
You can cast an enum value to its underlying integral type, and vice versa:
// Casting enum to int
int dayValue = (int)DayOfWeek.Friday; // dayValue will be 4
// Casting int to enum
DayOfWeek selectedDay = (DayOfWeek)3; // selectedDay will be DayOfWeek.Wednesday
// Casting to an invalid integer value
Status unknownStatus = (Status)10; // This is valid, but the enum member might not exist.
Console.WriteLine($"Unknown status value: {(int)unknownStatus}"); // Output: Unknown status value: 10
Example: Using Enums in a Switch Statement
Enums are particularly useful in switch statements for handling different states or options in a clear and structured way.
public void ProcessDay(DayOfWeek day)
{
switch (day)
{
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
Console.WriteLine("It's the weekend!");
break;
case DayOfWeek.Monday:
Console.WriteLine("Start of the work week.");
break;
default:
Console.WriteLine($"It's a weekday: {day}");
break;
}
}
Enum Flags
Sometimes, you need to combine multiple enum values. This is where enum flags come in handy. To create an enum that supports flags, you should:
- Decorate the enum with the
[Flags]attribute. - Assign power-of-two values (1, 2, 4, 8, etc.) to the enum members.
- Use bitwise operators (
|for combining,&for checking) to manipulate the enum values.
[Flags]
public enum FilePermissions : byte
{
None = 0,
Read = 1, // 00000001
Write = 2, // 00000010
Execute = 4, // 00000100
All = Read | Write | Execute // 00000111 (7)
}
// Usage:
FilePermissions userPermissions = FilePermissions.Read | FilePermissions.Write;
Console.WriteLine($"User has permissions: {userPermissions}"); // Output: User has permissions: Read, Write
// Check for a specific permission
if ((userPermissions & FilePermissions.Read) == FilePermissions.Read)
{
Console.WriteLine("User has read permission.");
}
// Check if All permissions are set
if (userPermissions == FilePermissions.All)
{
Console.WriteLine("User has all permissions.");
}
else
{
Console.WriteLine("User does not have all permissions.");
}
Important Note on Flags
When using flags, it's crucial to assign power-of-two values. If you don't, bitwise operations may not produce the expected results. Also, for flag enums, it's good practice to include a None member with a value of 0.
Enum Methods
The System.Enum class provides several useful static methods for working with enums:
Enum.GetName(typeof(MyEnum), value): Gets the string name of the enum member with the specified value.Enum.GetValue(typeof(MyEnum), name): Gets the underlying value of the enum member with the specified name.Enum.IsDefined(typeof(MyEnum), value): Checks if a specific value is defined for the enum.Enum.GetNames(typeof(MyEnum)): Returns an array of strings containing the names of all enum members.Enum.GetValues(typeof(MyEnum)): Returns an array of all enum values.Enum.Parse(typeof(MyEnum), name): Converts the string representation of an enum member to its equivalent enum value.
// Using Enum methods
string dayName = Enum.GetName(typeof(DayOfWeek), DayOfWeek.Tuesday);
Console.WriteLine($"The name for value 2 is: {dayName}"); // Output: The name for value 2 is: Tuesday
bool isDefined = Enum.IsDefined(typeof(Status), 2);
Console.WriteLine($"Is status value 2 defined? {isDefined}"); // Output: Is status value 2 defined? True
Status parsedStatus = (Status)Enum.Parse(typeof(Status), "Completed");
Console.WriteLine($"Parsed status: {parsedStatus}"); // Output: Parsed status: Completed
Benefits of Using Enums
- Readability: Replaces magic numbers with meaningful names.
- Maintainability: Easier to update and manage a set of related constants.
- Type Safety: Prevents assigning invalid integral values to variables that should only hold specific named constants.
- Self-Documenting Code: Enum names clearly indicate the purpose of the data.
Tip: Enum and String Conversion
While Enum.Parse and Enum.GetName are useful, be mindful of case sensitivity and potential exceptions if the string doesn't match an enum member. Consider using Enum.TryParse for safer string conversions.