C# enumeration type trouble

For all of my (rather short) time programming I have never quite understood the purpose of enumeration type nor how to properly use it.

Then I had written a class that worked something like this:

using UnityEngine;
using System.Collections;

public class MenuManager : MonoBehaviour 
{
	private int play = 0;
	private int options = 1;
	private int credits = 2;
	private int scoring = 3;
	private int quit = 4;

	void OnEnable()
	{
		MenuArrowMovement.eMenuSelected += OnMenuSelected;
	}

	void OnDisable()
	{
		MenuArrowMovement.eMenuSelected -= OnMenuSelected;
	}

	void OnMenuSelected(int selection)
	{
		if(selection == play)
		{
			//PlayGame();
		}

		if(selection == options)
		{
			//ShowOptions();
		}

		if(selection == credits)
		{
			//ShowCredits();
		}

		if(selection == scoring)
		{
			//ShowScoring();
		}

		if(selection == quit)
		{
			//QuitGame();
		}
	}
}

And I thought to myself, this is probably where Enumeration comes in handy! And so I tried it:

private enum MenuOptions {Play, Options, Credits, Scoring, Quit};

if (selection == MenuOptions.Play)
//do stuff

That didn’t build, of course. Can’t compare int and enum.

But then what value does MenuOptions.Play contain, I thought it was supposed to be int by default?

Debug.Log(MenuOptions.Play);

Console writes Play
:face_with_spiral_eyes: hm, ok. I expected it to be 0. I’m back to square one then.
What the heck do you use enums for if not for a situation like this, where you want to give numerical value to some variables, so that you can then have a more readable code? The only examples I see when searching the net are for week days, which are rather irrelevant to my needs.

So TL;DR Can I use enums in the example above to achieve my needs, and if so how?
And can someone provide an example where enums would be used in a script relating to a game, and not calendars.
Thanks for any advice!

Well if you’re going to be passing an integer as an argument, that kind of defeats the point of using an Enum, which is a friendly format for having constant values in your project. Passing in an integer is not so friendly, nor is it very readable to anyone looking at your code.

So change your onMenuSelected method to be…

void OnMenuSelected(MenuOptions selection)
{
   if(selection == MenuOptions.Play)
    //Show play
}
Debug.Log(MenuOptions.Play);

Console writes Play
:face_with_spiral_eyes: hm, ok. I expected it to be 0. I’m back to square one then.

When you use Debug.Log it calls “ToString” and on an enum that outputs the Key and not the Value. But, you can cast an Enum to an int… so if you did:

Debug.Log((int)MenuOptions.Play);

That would output 0.

Enums allow you to do things in a friendly manner without storing magic strings (hardcoded strings). So let’s say you want some kind of menu option (as you have above). It’s a lot nicer to say:

if(selection == MenuOptions.Play);

than it is to say:

if(selection == “Play”);

Leltdown is correct… you need your parameter to be of type MenuOptions. However, let’s say your parameter is an int. You can convert it to the type you need by simply casting it:

public void someMethod(int someValue)
{
    var menuOption = (MenuOptions)someValue;

    switch(menuOption)
    {
            case MenuOptions.Play:
                   //do cool stuff here
                  break;
    }
}

Now, let’s say your menu has a string value… you can also convert that to your enum:

public void someMethod(string someValue)
{
    MenuOptions menuOption;
    Enum.TryParse(someValue, out menuOption;
  
    //do your enum checks again now with menuOption.
}

Enums give you some advantages:

  1. They’re value types… so you’re not passing around strings and creating allocations.
  2. They’re strongly typed so by using an enum you’re restricting your values to the set you specify
  3. They reduce errors (typos) since intellisense will help you complete them and the compiler will catch mistakes for you.
  4. They can be casted to / from “int” so you can serialize and store the values in a compact way and easily revert to them.

to add 2 to dustin horne’s advantage list:
they can (and should be) switched instead of if’ed. put a default case in the switch and let it print a debug log to notify you of not handled values.
they can be foreached to automate processes. fe i use an enum in a messenger and fill the dictionary with delegates for each value automatically.

basically they should be used anywhere where you use distinct states (fsm’s fe). .net/mono and unity also uses them all over the place as function parameters fe how to open a file, translate relative to local space or world space or as flags like the layer.

Ohhh, I see what I’ve been missing. Thanks guys, this clears it up. Hopefully I’ll get it ironed out once I use it a few times in my code, now that I know how to properly implement it :slight_smile:

Good good. :slight_smile: It also is an indicator of intent. So just like I mentioned with reducing string errors before… it also is a good aid when you have multiple developers because you are telling the other developers: “This is the range of values that I accept”. It’s somewhat self-documenting in that regard.

Enums can also have a few different base types but as you’re just starting out with them just use them as the default in which the underlying base type is “int”. Here’s another plus… Let’s say you have a method that accepts a player’s state:

public void SetPlayerState(string state)
{

}

In the case above we’re accepting it as a string… and here’s where it gets really fun. Let’s say we want to change the state to “RunningLikeHell”. So if we look at how this is allocated or stored… strings in .NET are Unicode (UTF16). Each is represented by 2 bytes. So the string above is actually 30 bytes (15 characters). But that’s not all… strings are reference types and based on object… There is 20 bytes of overhead just for creating a string which contains information about the length of the string, a null terminator, the pointer to the string, and something else that I can’t remember off the type of my head.

Ok, so that all being said… you’re now allocating 50 bytes of memory and it’s a reference type so it’s subject to garbage collection… just to pass a player state to the function. Instead you can have this:

public enum PlayerState
{
      Idle,
      Walking,
      Sleeping,
      RunningLikeHell
}

Since Enum’s are the size of their underlying type (int in this default instance), The values of this enum are represented by only 4 bytes. So you can write your function:

public void SetPlayerState(PlayerState state)
{
    //change based on the state of the player
}

So now you know that you’re only passing 4 bytes into the function! Now something to keep in mind is that Enum is a value type. In the case the string you are allocating 50 bytes… but you’re only passing 4 bytes to the function because it really only passes the pointer to the original string that is stored on the heap. In the case of the Enum you’re passing the same 4 bytes only this time it is a copy of the enum value since it’s a value type.

So the final breakdown.

String: allocated 50 bytes → passed 4 bytes (32-bit integer pointer) to the function
Enum: allocated 4 bytes → passed 4 bytes (32-bit copy of the underlying value) to the function

AND you haven’t allocated anything new for the garbage collector. :slight_smile:

I believe more than 50 bytes would actually be allocated for the string as well… because I think .NET does something with byte alignment for allocation of reference types that has to be a multiple of 32-bits but I don’t know exactly how that works.

If you’re curious of the impact you can create a console app in visual studio and just use the following code:

static void Main(string[] args)
        {
            //Get the byte length of your string
            var sz = UnicodeEncoding.Unicode.GetBytes("RunningLikeHell").Length;

            //Add 20 bytes for overhead
            sz += 20;

            //Write to the console
            Console.WriteLine("Total allocated: {0} bytes", sz);
            Console.ReadKey();
        }