Home
Map
enum ExamplesStore named and magic constants with enums. Use enums in collections, if and switch.
C#
This page was last reviewed on May 13, 2023.
Enum. Think of a program that stores representations of flowers. A flower may have a purple color. An enum could represent colors—this is more robust than a string.
In a C# program, we must specify an enum in a way similar to a class. And then we can reuse it wherever needed. Enums are like ints with added compiler checks.
Enum example. Here is an enum that expresses importance. An enum type internally contains an enumerator list. The values (like Trivial and Critical) are ints like 1 and 4.
Step 1 We specify an enum variable and assign it to Importance.Critical. This is like an int, but with special constraints.
Step 2 We test the enum value with an if-statement. The value is Critical, so "True" is printed.
using System; class Program { enum Importance { None, Trivial, Regular, Important, Critical } static void Main() { // Step 1: create an enum local. Importance value = Importance.Critical; // Step 2: test against a known Importance value. if (value == Importance.Critical) { Console.WriteLine(true); } } }
True
Parse. Sometimes we have a string value that we want to convert to an equivalent enum. We invoke the Enum.Parse generic method to perform this conversion.
Tip When using .NET, calling a built-in method to do conversions (where one exists) is usually best.
Enum.Parse
using System; class Program { enum PetType { None, Cat, Dog } static void Main() { string test = "Dog"; // Get enum from string. PetType result = Enum.Parse<PetType>(test); Console.WriteLine(result); } }
Dog
Debugger. We examine what enums look like in the Visual Studio debugger. We see that enums are each a separate type. The debugger shows that tagValue is of type Program.TagType.
Info Because each enum type is separate, we cannot become confused and try to change a VehicleType into a PetType.
using System; class Program { enum TagType { None, BoldTag, ItalicsTag, HyperlinkTag } static void Main() { // Specify a tag instance. TagType tagValue = TagType.BoldTag; if (tagValue == TagType.BoldTag) { // Will be printed. Console.WriteLine("Bold"); } if (tagValue == TagType.HyperlinkTag) { // This is not printed. Console.WriteLine("Not true"); } } }
Bold
Enum advantages. With an enum, magic constants are separate. This modular design makes things easier to understand. Fewer bugs will be introduced.
Start Consider this program—the color Blue is supposed to have the value 9001. We can store this in an enum to ease maintenance.
using System; enum CaseColor { Uncolored = 0, Red = 8001, Blue = 9001 } class Program { static void Main() { // This makes sense to read. Console.WriteLine("COLOR: {0}, {1}", CaseColor.Blue, (int)CaseColor.Blue); // This is more confusing to read. Console.WriteLine("COLOR: {0}, {1}", "Blue", 9001); } }
COLOR: Blue, 9001 COLOR: Blue, 9001
Strings. We convert enums to strings for display on the Console. Enum values always have a name, such as TagType.None (in the above example).
Tip To print out the enum values, you can call ToString on the enum variable in a program.
Also Another method such as Console.WriteLine can automatically call the ToString method.
enum ToString
class Program { enum Visibility { None, Hidden = 2, Visible = 4 } enum AnimalType { None, Cat = 1, Dog = 2 } static void Main() { // ... Two enum variables. AnimalType animal = AnimalType.Dog; Visibility visible = Visibility.Hidden; // ... Use Console.WriteLine to print out heir values. System.Console.WriteLine(animal); System.Console.WriteLine(visible); } }
Dog Hidden
Switch. We often use if-statements with enums. But switch is another option. And switch is sometimes compiled to more efficient IL.
switch enum
Info IsFormat() works as a filter that tells us something about sets of enum values—it contains a switch statement.
Tip We can separate the logic here instead of repeating ourselves. This helps clarify the program logic.
using System; class Program { enum FormatType { None, BoldFormat, // Is a format value. ItalicsFormat, // Is a format value. Hyperlink // Not a format value. } static void Main() { // ... Test enum with switch method. FormatType formatValue = FormatType.None; if (IsFormat(formatValue)) { // This is not reached, as None does not return a true value in IsFormat. Console.WriteLine("Error"); } // ... Test another enum with switch. formatValue = FormatType.ItalicsFormat; if (IsFormat(formatValue)) { // This is printed, as we receive true from IsFormat. Console.WriteLine("True"); } } /// <summary> /// Returns true if the FormatType is Bold or Italics. /// </summary> static bool IsFormat(FormatType value) { switch (value) { case FormatType.BoldFormat: case FormatType.ItalicsFormat: { // These 2 values are format values. return true; } default: { // The argument is not a format value. return false; } } } }
True
Default. Values are always initialized to zero when they are fields of a class. Upon class creation, an enum field will also be initialized to zero (and the equivalent value).
Tip To make enums valid, always use the default value of zero. This way, we can test for the default value of fields.
Tip 2 You can place a semicolon at the end of an enum block (but this is not required or helpful usually).
using System; enum CatFurColor { None, Orange, Grey }; class Program { static CatFurColor _color; static void Main() { // The enum is a field, so it has its default value of None. Console.WriteLine("DEFAULT ENUM VALUE: {0}", _color); } }
DEFAULT ENUM VALUE: None
Collections. Here we apply the Stack collection in .NET. With Stack, we can develop a parser that keeps the most recently encountered enum value on the top.
Here The Stack can only have TagType values added to it. This is an example of type checking and validation.
Stack
Note With the Pop method we get the top element from the stack. This is of type TagType.ItalicsTag.
Result In the execution of this program, the stack has two enums added and one removed.
using System.Collections.Generic; class Program { enum TagType { None, // integer value = 0 BoldTag, // 1 ItalicsTag, // 2 HyperlinkTag, // 3 } static void Main() { // Create a Stack of enums. var stack = new Stack<TagType>(); // ... Add enum values to our Stack. stack.Push(TagType.BoldTag); // Add bold. stack.Push(TagType.ItalicsTag); // Add italics. // ... Get the top enum value. TagType thisTag = stack.Pop(); // Get top tag. System.Console.WriteLine("POP RESULT: " + thisTag); // Peek at the top. var peeked = stack.Peek(); System.Console.WriteLine("PEEK RESULT: " + peeked); } }
POP RESULT: ItalicsTag PEEK RESULT: BoldTag
Type. An enum has an underlying type. Each time we use the enum, we are using the underlying type. The enum has syntactic sugar on top.
Tip Enums are by default an int type, but we can adjust this to a different numeric type.
Here We create an enum with a type of byte. This is sometimes useful on small enums. A byte can only contain 256 different values.
byte, sbyte
Info The CoffeeSize enum will use memory equivalent to a byte. This can make classes more efficient and smaller.
using System; class Program { enum CoffeeSize : byte { None, Tall, Venti, Grande }; static void Main() { // ... Create a coffee size local. CoffeeSize size = CoffeeSize.Venti; Console.WriteLine(size); } }
Venti
GetUnderlyingType. We can determine an enum's type (like int) at runtime. Enum.GetUnderlyingType, a static method, determines the underlying type.
static
Next We declare an enum Importance. For this example it uses an underlying type of byte.
Then When the GetUnderlyingType method is called, the System.Byte type is returned.
using System; class Program { enum Importance : byte { Low, Medium, High }; static void Main() { // Determine the underlying type of the enum. Type type = Enum.GetUnderlyingType(typeof(Importance)); Console.WriteLine(type); } }
System.Byte
Null, none. An enum value cannot be null. It is a value type like an int. To avoid the "cannot convert null" error, use a special None constant as the first enum item.
enum Color { None, Blue, Red } class Program { static void Main() { Color c = null; } }
Error CS0037 Cannot convert null to 'Color' because it is a non-nullable value type
enum Color { None, Blue, Red } class Program { static void Main() { Color c = Color.None; } }
Flags. The C# language allows us to specify a Flags attribute on an enum. This enables the enum to be used as a bit field. We can use combinations of enum values this way.
enum Flags
Here We have an enum called DataInfo that has 4 different flag values. We set 2 of them at once in Main().
And In the if-statement, we find that OptionA and OptionC are set to true, but OptionB is not set. This is the correct result.
using System; class Program { [Flags] enum DataInfo { None = 0, OptionA = 1, OptionB = 2, OptionC = 4, } static void Main() { var info = DataInfo.OptionA | DataInfo.OptionC; // See if current flag is set. if ((info & DataInfo.OptionA) == DataInfo.OptionA && (info & DataInfo.OptionB) != DataInfo.OptionB && // Not OptionB. (info & DataInfo.OptionC) == DataInfo.OptionC) { Console.WriteLine("Has OptionA, OptionC, but not OptionB."); } } }
Has OptionA, OptionC, but not OptionB.
Benchmark, enum. Enums are fast. They are almost never a performance concern. They are just syntactic sugar on a type like int, which is also fast.
Version 1 This version of the code tests for an enum value. We run it in a tight loop for many iterations.
Version 2 This codes tests an int. By comparing these versions of the code, we can see any possible performance impact from enums.
Result The enum test takes the same amount of time as the int test—the enum carries no performance penalty over int.
using System; using System.Diagnostics; class Program { enum TestType { None, Valid, Invalid } const int _max = 10000000; static void Main() { // Version 1: use enum in if-statement. var s1 = Stopwatch.StartNew(); var temp1 = TestType.Valid; for (int i = 0; i < _max; i++) { if (temp1 == TestType.Invalid) { return; } } s1.Stop(); // Version 2: use int in if-statement. var s2 = Stopwatch.StartNew(); var temp2 = 0; for (int i = 0; i < _max; i++) { if (temp2 == 2) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } }
0.27 ns if enum 0.27 ns if int
IL, enum. We can determine the exact performance of enums by examining the IL (intermediate language) of a compiled C# program. Enums are loaded with ldc.i4.
And This means "load constant integer of 4 bytes." So an enum of just a constant 4-byte integer, exactly like any other const int.
Detail This has an enum, 3 const ints, and 3 static readonly ints. The IL shows how the values are loaded onto the evaluation stack.
Result Enums and const ints are loaded with ld.c, so they perform the same. But static ints are loaded with ldsfld, which is slower.
using System; enum Test { Cat, Dog, Rabbit } class Program { const int _cat = 0; const int _dog = 1; const int _rabbit = 2; static readonly int _cat2 = 0; static readonly int _dog2 = 1; static readonly int _rabbit2 = 2; static void Main() { Method(Test.Cat); Method(Test.Dog); Method(Test.Rabbit); Method(_cat); Method(_dog); Method(_rabbit); Method(_cat2); Method(_dog2); Method(_rabbit2); } static void Method(Test test) { } static void Method(int value) { } }
.method private hidebysig static void Main() cil managed { .entrypoint .maxstack 1 L_0000: ldc.i4.0 L_0001: call void Program::Method(valuetype Test) L_0006: ldc.i4.1 L_0007: call void Program::Method(valuetype Test) L_000c: ldc.i4.2 L_000d: call void Program::Method(valuetype Test) L_0012: ldc.i4.0 L_0013: call void Program::Method(int32) L_0018: ldc.i4.1 L_0019: call void Program::Method(int32) L_001e: ldc.i4.2 L_001f: call void Program::Method(int32) L_0024: ldsfld int32 Program::_cat2 L_0029: call void Program::Method(int32) L_002e: ldsfld int32 Program::_dog2 L_0033: call void Program::Method(int32) L_0038: ldsfld int32 Program::_rabbit2 L_003d: call void Program::Method(int32) L_0042: ret }
GetName, Getnames. Built-in methods get strings that represent enums. With GetName, we can get the name for an enum value. With GetNames we get all the string representations at once.
Enum.GetName
Format enums. It is possible to format the values stored in enums in different ways. We can display an integer representation, or a hex representation.
Enum.Format
Arrays. Enums are values. We can use enums to index arrays. This approach is useful for some kinds of tables or data structures in programs.
enum Array
Memory notes. A small underlying type (such as byte) will make class instances that hold an enum smaller. Thousands of class instances are required before this optimization is important.
Enums enhance clarity and reduce the probability of invalid constants. We use them to represent constant values (such as integers) in a consistent way.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on May 13, 2023 (simplify).
Home
Changes
© 2007-2024 Sam Allen.