Enumerations

Enumerations

The Crash Course

  • Enumerations are a way of defining your own type of variable so that it has specific values.
  • Enumerations are defined like this: public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
  • Enumerations should be defined outside of any classes that you have.
  • The fact that an enumeration can only take on the values that you chose, means that you can't possibly end up with bad data that is meaningless.
  • You can assign your own numeric values to the items in an enumeration: public enum DayOfWeek { Sunday = 5, Monday = 6, Tuesday = 7, Wednesday = 8, Thursday = 9, Friday = 10, Saturday = 11 };

Introduction

We've been going at a pretty fast pace, with lots covered in each tutorial. This one will be a bit of a break, though, as enumerations a pretty simple and easy.

Enumerations (or enumeration types, or enums for short) are a cool way to define your own type of variable (the first of many ways we'll see to create your own).

The word enumeration comes from the word enumerate, which means "to count off, one after the other", which is basically what we're going to be doing. We're going to start off with the basics of using enumerations, but then we'll come back and discuss why enumerations are so valuable. We'll do this so that it makes more sense what an enumeration is before trying to explain how helpful they are. Then we'll go back to some of the details of using an enumeration before the end.

The Basics of Enumerations

Let me start off with an example of when enumerations may be helpful. Let's say you are keeping track of something that has a known, small, specific set of possible values that you can use—for instance, the days in the week. You know, Sunday, Monday, Tuesday, etc. One way you could do this is to define Sunday to be 1, Monday to be 2, Tuesday to be 3, and so on.

So your code could look something like this:

int dayOfWeek = 3;
 
if(dayOfWeek == 3)
{
    // Do something here because it is Tuesday.
}

Or better yet, for the sake of readability, you might create a variable to store each of these days:

int sunday = 1;
int monday = 2;
int tuesday = 3;
int wednesday = 4;
int thursday = 5;
int friday = 6;
int saturday = 7;
 
int dayOfWeek = tuesday;
 
if(dayOfWeek == tuesday)
{
    // Do something here because it is Tuesday.
}

This kind of situation, though, is exactly what enumerations are for. You create an enumeration and list the possible values it can have.

Importantly, making an enumeration is our first real experience defining a new type. That is, by defining a new enumeration, we are literally making something like int or string! We'll see plenty of other ways to make new types in the future, but enumerations are a good starting point because of how simple they are.

Because we are making a whole new type, we can't just place an enumeration definition just anywhere in our program.

There are two places we can put out enumeration. One option is to put it into its own file. I'm not going to go through that approach here, but I strongly suspect you could probably poke around in Visual Studio (or whatever editor you're using) and figure it out easily if you'd rather take that approach.

We're still not building very big programs right now, and it is convenient to keep small programs all in a single file to keep them easier to manage. (But in a few more tutorials, we'll start putting things in other files. We'll get there soon enough.)

But defining a new type, like an enumeration, is not just any old statement. We can't just put it wherever we want in our .cs file. Instead, we'll place any new types we define at the bottom of our Program.cs file, below all other statements we want our program to do.

So to start, we might make something like this:

Console.WriteLine("Hello, World!");
 
public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

Once we've put our new enumeration into our program, our main method, where our other statements go (the Console.WriteLine("Hello, World!"); above), we can start to use it.

For example, we can declare a variable whose type is DayOfWeek:

DayOfWeek today;
 
public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

today is a variable that can hold DayOfWeek values—our newly created enumeration type!

For the built-in types, we've usually assigned values by using literals. For example an int literal like 1 or a string literal like "Hello". For an enumeration type, we have to get a bit fancier:

DayOfWeek today = DayOfWeek.Tuesday;
 
public enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

We name the value we want to use by accessing it through the enumeration type name, followed by a ., followed by the specific value we want to use.

Enumerations are fairly simple and thus limited types. We can't do things like multiply or add them. They represent, simply, a collection of specific, allowed values. But one thing we can and will often do with enumeration values is compare them against each other or against known values:

DayOfWeek today = DayOfWeek.Tuesday;
 
if (today == DayOfWeek.Saturday || today == DayOfWeek.Sunday)
{
    Console.WriteLine("It's the weekend!");
}
else if (today == DayOfWeek.Wednesday)
{
    Console.WriteLine("It is Wednesday, my dudes.");
}
else if (today == DayOfWeek.Monday)
{
    Console.WriteLine("Just another manic Monday.");
}
else
{
    Console.WriteLine("Just a regular " + today);
}

You can see that we can check enumeration values against each other for equality. We can also use !=, and, interestingly, we can use <, >, <=, and >=, which uses the order the items are defined in the enumeration itself for ordering. Do be careful when you use these because often, a set of distinct values like these are not meant to convey order, just identifying possible values without order.

The last pathway shows using the enumeration value in conjunction with a string and a Console.WriteLine. Whenever the C# compiler sees you attempting to combine a string with something else using the + symbol (called concatenation), it will automatically convert the non-string to a string representation and then put the two together. The string representation of enumeration values will be their representation in code, so DayOfWeek.Tuesday will become the string "Tuesday". That's exactly what we want here, but may not always be.

Enumerations and Switches

Switches and enumerations very often are used together. The code we had above could have also been written like this:

DayOfWeek today = DayOfWeek.Tuesday;
 
switch (today)
{
    case DayOfWeek.Saturday:
    case DayOfWeek.Sunday:
        Console.WriteLine("It's the weekend!");
        break;
    case DayOfWeek.Wednesday:
        Console.WriteLine("It is Wednesday, my dudes.");
        break;
    case DayOfWeek.Monday:
        Console.WriteLine("Just another manic Monday.");
        break;
    default:
        Console.WriteLine("Just a regular " + today);
        break;
}

And if you want to ask the user to pick one of your enumeration options, you could write code like this:

Console.Write("Type a day of the week: ");
string typedDay = Console.ReadLine();
DayOfWeek today = typedDay switch
{
    "Sunday" => DayOfWeek.Sunday,
    "Monday" => DayOfWeek.Monday,
    "Tuesday" => DayOfWeek.Tuesday,
    "Wednesday" => DayOfWeek.Wednesday,
    "Thursday" => DayOfWeek.Thursday,
    "Friday" => DayOfWeek.Friday,
    "Saturday" => DayOfWeek.Saturday
};

A couple of notes on that…

First, that's using a switch expression rather than a switch statement. This type of conversion is well-suited to switch expressions.

Second, this code doesn't handle garbage data. If you don't enter one of the specifically listed options, this code won't work. Even something like "sunday" would fail here. You could include options for different capitalizations and do something like string typedDay = Console.ReadLine().ToLower();, which takes the text returned by ReadLine() and changes all characters to lowercase before storing it in typedDay. After that, you could just check only the all-lowercase versions of each day of the week in the switch, and handle any style of capitalization, including "Sunday", "sunday", "SUNDAY", and "SuNDaY". But even that doesn't allow us to handle something like "Sun" or "blarg!". We could use a _ (or a default in a switch statement) to handle all other cases and just pick a random day. But we'll also learn better error handling tools later.

For the short term, assuming that the user will enter good data is probably fine. As a general rule, that's a really bad idea. But right now, the only user is probably you, and the most severe consequence is going to be having to re-run your program, which you'll know how to do. So the stakes are extremely low right now, and going light on error handling is not the end of the world.

Why Enumerations are Useful

The main problem that enumerations solve is ensuring that we're working only with a very limited set of named options. If we were just using int instead, we'd run the risk that we could accidentally do something like dayOfWeek = 57347;, which doesn't make sense. Defining an enumeration and listing the allowed values gives us a lot of control over how it is used, making it "safer" and less bug-prone. That's a huge win.

Some More Details of Enumerations

If you're in a hurry, feel free to skip this section.

Before we move on, I want to point out that enumerations are essentially just numbers with a layer of compiler magic on top of them.

The compiler will let you cast from an enumeration to an int or vice versa:

int dayAsInt = (int)DayOfWeek.Sunday;
DayOfWeek today = (DayOfWeek)dayAsInt;
DayOfWeek tomorrow = (DayOfWeek)(dayAsInt + 1);

An explicit cast is required to go in either direction.

If you are going from an enumeration to an int, you're losing the stronger notion that it means something beyond just a numeric value. If you go from int to enumeration, the danger is that the int value you're casting may not actually map to one of the enumeration values, which could leave you in a pickle since the value won't equal any of the ones listed in the enumeration. You could end up with a DayOfWeek that is 2000!

By default, the first item in the enumeration is equivalent to the number , the second is equivalent to 1, and so on. But if you want to pick alternative numbers, you can do so:

public enum DayOfWeek { Sunday = 5, Monday = 6, Tuesday = 7, Wednesday = 8, Thursday = 9, Friday = 10, Saturday = 11 };

I try to avoid this when I can. If the things are numbers at heart, I usually use int or another number type. If they are truly enumerations, then usually, there isn't a great mapping to numbers, and starting with zero is as good as anything. But it does have its uses.

What's Next?

Enumerations are only the first of many ways that we'll see to make your own type of variables. There are lots of cool ways you can use enumerations, like the type of terrain you are using for a tile in your game (public enum TerrainType { Mountain, Water, Desert, Grassland, Forest };) or the suits of a deck of playing cards (public enum Suit { Clubs, Diamonds, Spades, Hearts };).

We've now covered many of the very basic topics in C#, and we're ready to start getting into some of the more advanced features that will really let us create powerful and awesome programs. Our next stop is an important one: methods.