Skip to content
Theory · Enums, records and patterns · lesson 1 of 8

Enums

What you'll learn

What you'll learn:

  • declare an enum and pick one value from its list;
  • describe data with a record and compare records by their contents;
  • get a changed copy of a record with a with expression;
  • check values with patterns in is and in a switch expression, remembering that arms are checked from top to bottom.
A rack for the stamps Small, Medium and Large: the Medium stamp is out, and the box beside it bears its imprint Medium

Think of a delivery company's warehouse. The box size there is not written by hand but stamped on, and the rack holds exactly three stamps: "small", "medium" and "large". A stamp cannot print a word of your own, so a typo like "meduim" never gets onto a box.

Without the stamps, the size would be written by hand, and in a program it would have to be stored as a string or a number. The string "Meduim" with its typo compiles without a single warning. The number 1 tells the reader nothing: is that the small box or the medium one?

A type that has only values named in advance is called an enumeration. In C#, you declare it with the word enum:

C#
Size box = Size.Medium;
Console.WriteLine(box); // Medium

if (box == Size.Medium)
{
    Console.WriteLine("medium box"); // medium box
}

enum Size { Small, Medium, Large }

Let's take the program apart line by line:

  1. enum Size { Small, Medium, Large } declares the type Size with three values. Like a class, an enum is declared after the top-level statements.
  2. Size box = Size.Medium; creates a variable of type Size. You write the value with a dot: the enum's name, then the value's name.
  3. Console.WriteLine(box) prints the value's name: Medium.
  4. box == Size.Medium compares two enum values and gives true, so the if branch runs.

Declaring an enum

Let's take the declaration enum Size { Small, Medium, Large } apart:

  • enum is a keyword: the name of a new type follows it;
  • Size is the type's name, capitalized like a class name;
  • Small, Medium, Large are the members of the enum, separated by commas inside braces; they are capitalized too.

Now the compiler catches the typo. The line Size box = Size.Meduim; fails to compile with error CS0117: the type Size has no member Meduim.

A number behind each name

Inside, an enum stores a whole number of type int. The members are numbered in order from zero: Small is 0, Medium is 1, Large is 2. You get the number with an (int) cast, and a cast to the enum type leads back from a number to a member:

C#
Console.WriteLine((int)Size.Large);      // 2
Console.WriteLine((Size)1);              // Medium
Console.WriteLine((int)Status.Archived); // 6

enum Status { Draft = 1, Published = 5, Archived }

You can also set a number yourself, as in Draft = 1. A member without a number gets the previous member's number plus one, so Archived is 6.

Interviewers like to ask what an enum stores inside. The answer: a whole number, while the names are there for reading the code and for printing. Unless you give the number another type, it is an int. The default value of any enum is 0. If no member has the number 0, as in Status, the default value prints as the digit 0.

A number without a name

This is where the stamp analogy breaks down. You cannot use a stamp the rack doesn't have. An enum variable has no such protection: with a cast, you can put any int into it, even one without a name.

C#
Size odd = (Size)7;
Console.WriteLine(odd); // 7

Console.WriteLine(odd switch
{
    Size.Small => "S",
    Size.Medium => "M",
    Size.Large => "L",
    _ => "unknown",
}); // unknown

The compiler doesn't check whether the number has a name: the cast is explicit, and you are responsible for it. Console.WriteLine prints a value without a name as digits, so the output is 7.

An enum variable can hold a number without a name, so a switch expression over an enum needs a _ arm even when every member has its own arm. Without it, the compiler warns with CS8524: a number without a name, such as (Size)3, is not handled.

Common mistake

A number was put into an enum variable without a cast:

C#
Size box = 2; // ✗
Console.WriteLine(box);

enum Size { Small, Medium, Large }
TEXT
error CS0266: Cannot implicitly convert type 'int' to 'Size'. An explicit conversion exists (are you missing a cast?)

The program doesn't compile. A number does not turn into an enum by itself; otherwise a stray 2 would quietly become a box size. You need an explicit cast, (Size)2, or better, the member's name: Size.Large. There is one exception, zero: the compiler converts the literal 0, or a const equal to zero, to any enum without a cast.

Key points

  • enum declares a type with a fixed set of named values: enum Size { Small, Medium, Large }.
  • Every member stands for an int: 0, 1, 2 in order by default, and (int)Size.Large gives 2.
  • Console.WriteLine prints a member's name, and a number without a name as digits: (Size)7 prints as 7.
  • A number gets into an enum through an explicit cast: Size box = 2; doesn't compile.