iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Enums

C# enums are typed labels for integral values. Combined with [Flags] for bitwise compositions, conversion helpers, and switch expressions, they cover status codes, permission masks, parsing, and any closed set you want compile-time safety on.

Definition, Flags, conversion, switch

EXAMPLE
// 1) Basic enum
public enum Direction { North, East, South, West }

Direction d = Direction.North;
d.ToString();                              // 'North'
(int)d;                                     // 0

// Underlying type — default is int; can specify
public enum Status : byte { Active = 1, Inactive = 0, Pending = 2 }

// 2) Switch expressions (exhaustive)
static string Describe(Direction d) => d switch
{
    Direction.North => "up",
    Direction.East  => "right",
    Direction.South => "down",
    Direction.West  => "left",
    _               => "unknown",
};

// In C# 11+ with switch on enums, the compiler warns when cases are missing.

// 3) Enum with explicit values + parsing
public enum HttpStatus
{
    OK = 200,
    Created = 201,
    NoContent = 204,
    BadRequest = 400,
    Unauthorized = 401,
    NotFound = 404,
    InternalServerError = 500,
}

HttpStatus s = (HttpStatus)200;
bool valid = Enum.IsDefined(typeof(HttpStatus), 999);   // false

if (Enum.TryParse<HttpStatus>("NotFound", out var parsed))
{
    // ok
}

// 4) [Flags] for bitwise composition
[Flags]
public enum Permissions
{
    None    = 0,
    Read    = 1 << 0,
    Write   = 1 << 1,
    Delete  = 1 << 2,
    Admin   = Read | Write | Delete,           // composite
}

var p = Permissions.Read | Permissions.Write;
bool canRead = p.HasFlag(Permissions.Read);   // true
bool canDelete = (p & Permissions.Delete) != 0;

Console.WriteLine(p);                          // 'Read, Write'   (ToString respects [Flags])

// Add / remove flags
p |= Permissions.Delete;                       // add Delete
p &= ~Permissions.Write;                        // remove Write

// 5) Iterating values
foreach (var dir in Enum.GetValues<Direction>())
{
    Console.WriteLine(dir);
}

string[] names = Enum.GetNames<Direction>();   // 'North', 'East', 'South', 'West'

// 6) Display names + descriptions
using System.ComponentModel;
using System.Reflection;

public enum OrderStatus
{
    [Description("Cart")]              Pending,
    [Description("Awaiting payment")]  AwaitingPayment,
    [Description("Paid + ready")]      Paid,
}

public static string GetDescription<T>(T value) where T : Enum
{
    var member = typeof(T).GetMember(value.ToString());
    var attr = member[0].GetCustomAttribute<DescriptionAttribute>();
    return attr?.Description ?? value.ToString();
}

GetDescription(OrderStatus.AwaitingPayment);  // 'Awaiting payment'

// 7) JSON — System.Text.Json string enum converter
using System.Text.Json.Serialization;
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Role { Guest, User, Admin }

// Or globally:
var options = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } };

// 8) EF Core — store enum as string
modelBuilder.Entity<User>()
    .Property(u => u.Role)
    .HasConversion<string>();

// Storing as string survives reordering values; storing as int can shift if you reorder.

// 9) Generic constraint where T : Enum
public static T Random<T>() where T : struct, Enum
{
    var values = Enum.GetValues<T>();
    return values[new Random().Next(values.Length)];
}

var randomDir = Random<Direction>();

// 10) Validate user input
public static Direction ParseDirection(string input)
{
    if (Enum.TryParse<Direction>(input, true, out var d) && Enum.IsDefined(d))
        return d;
    throw new ArgumentException($"Invalid direction: {input}");
}

// 11) Casting safely
int raw = 42;
if (Enum.IsDefined(typeof(HttpStatus), raw))
{
    var status = (HttpStatus)raw;     // OK to cast
}
else
{
    // unknown
}

// 12) Performance — HasFlag vs bitwise AND
// HasFlag boxes the enum in older runtimes (.NET Framework). In modern .NET (Core+), it's optimised.
// Bitwise AND is still slightly faster + zero-allocation:
if ((p & Permissions.Read) == Permissions.Read) { /* … */ }

// 13) Enum classes (struct alternative)
// For richer behaviour, use sealed records + a static class as an enum alternative
public sealed record StateMachineState
{
    public string Name { get; }
    public string DisplayName { get; }
    private StateMachineState(string n, string d) { Name = n; DisplayName = d; }

    public static readonly StateMachineState Pending  = new('pending',  'In review');
    public static readonly StateMachineState Approved = new('approved', 'Live');
    public static readonly StateMachineState Rejected = new('rejected', 'Closed');
}

// Useful when you need fields beyond a single integral.

// 14) Common bugs
// • Storing enum as int in DB then reordering values → data shifts; store as STRING (HasConversion<string>())
// • Forgetting [Flags] but using bitwise → ToString shows numeric value, debugging confusion
// • IsDefined inside hot loops → reflection cost; cache HashSet of valid values
// • Casting unrelated ints to enum without IsDefined check — invalid enum values in your code
// • Switch on enum without a default and missing cases → compiler warns; embrace it
// • Equals between unrelated enums — compile error (good); cast to int if you really mean to
// • Default(MyEnum) = 0; if 0 isn't a real value, you get an invalid state — always include 'None = 0' or similar
// • JSON deserialisation of unknown string → throws; configure to accept names + fallback default

Why it matters

C# enums earn their keep with [Flags] for permission masks, switch expressions for exhaustive matching, and HasConversion<string>() in EF Core so you can safely reorder values later. Always include a None = 0 entry, validate untrusted input with Enum.IsDefined, and reach for record-based “smart enums” when you need fields beyond a single integral value.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
enum Day { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
Day d = Day.Fri;
if (d == Day.Fri) Console.WriteLine("🎉");
Try it Yourself »

Discussion

Loading…