Achieving Optimal Utilization of Enum in C#

Introduction

Within the C# programming language, an enum, which is short for "enumeration," serves as a unique data type comprised of a group of named constants known as enumerators. Enums are employed to establish a series of interconnected integral constants, enhancing the readability and manageability of the code through the assignment of descriptive names to these constants.

Enums in C# provide numerous advantages

  1. Enhancing Readability and Maintainability: Enums enable the use of descriptive names for integral constants, enhancing the readability and clarity of the code. This, in turn, improves the maintainability of the codebase as developers can easily comprehend the purpose of each constant.
  2. Ensuring Type Safety: Enums offer type safety during compilation, restricting the assignment of values to variables within the predefined set of constants of that enum type. This feature helps in preventing errors resulting from the use of incorrect values.
  3. Compiler Assistance: Enum values undergo type checking by the compiler, ensuring that only valid enum constants are utilized. This aids in identifying errors at an early stage of the development process.
  4. Intellisense Support: Integrated Development Environments (IDEs) such as Visual Studio provide intellisense support for enums, facilitating easier interaction with them. Developers can view a list of available enum values and their descriptions while writing code.
  5. Facilitating Code Refactoring: Enum values can be modified, or new ones can be added without impacting other sections of the code. This flexibility offered by enums helps maintain consistency throughout the codebase.
  6. Compatibility with Switch Statements: Enums are well-suited for use with switch statements, enabling the creation of cleaner and more structured code for handling multiple cases.
  7. Minimizing Error Risks: By utilizing enums, the likelihood of errors caused by typos or incorrect values is reduced since enum constants are validated during compilation.

Features of enum

  1. An enumeration consists of a predetermined set of constants.
  2. Type safety is enhanced by the use of an enumeration.
  3. Enumerations can be iterated over.

Various implementations of enum are

Example 1

// Define an enum named WeekDays
public enum WeekDays
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

If no values have been assigned to the members of the enum, the first member is automatically assigned a value of 0. Subsequently, the values of the other members are incremented by 1.

Example 2

Integer values can also be explicitly assigned to enums.

public enum WeekDays
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7
}

Enums are valuable in situations where you possess a predetermined collection of interconnected values that are unlikely to undergo frequent alterations. Examples of such values include days of the week, months, status codes, and more. By offering compile-time type safety and utilizing descriptive names instead of arbitrary numbers or strings, enums can greatly enhance the readability of code.

Example 3

Within an enumeration, the numerical value assigned to its members can belong to any integral numeric data type such as byte, int, short, long, ushort, and others.

public enum ByteEnum : byte
{
    Value1,
    Value2,
    Value3
}

In this scenario, ExampleEnum is an enumeration where each element (Value1, Value2, Value3) is denoted by a byte value. The initial element (Value1) will be assigned a value of 0, the second element (Value2) will be assigned a value of 1, and so forth.

Utilizing byte as the fundamental type for enumerations can be advantageous when dealing with a restricted range of values that fall within the byte range (0 to 255). This approach can lead to memory conservation in comparison to utilizing larger integer types like int, particularly in situations where numerous enum variables exist or when memory efficiency is crucial, such as in embedded systems or low-level programming.

Note. By default, the enum members are of int type.

Example 4

Switch statements frequently utilize enums to compare against specific values.

public enum ByteEnum : byte
{
    Value1,
    Value2,
    Value3
}

private void SetSwitchStatementForEnum(ByteEnum byteEnum)
{
    switch (byteEnum)
    {
        case ByteEnum.Value1:
            break;
        case ByteEnum.Value2:
            break;
        case ByteEnum.Value3:
            break;
        default:
            break;
    }
}

Example 5

Iterating through all values using the getNames() method.

public enum WeekDays
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

public void SetEnumNames()
{
    foreach (string s in Enum.GetNames(typeof(WeekDays)))
    {
        Console.WriteLine(s);
    }
}

// Output
// Sun
// Mon
// Tue
// Wed
// Thu
// Fri
// Sat

Example 6

Traversing all values using the getValues() method.

public enum WeekDays
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

public void SetEnumNames()
{
    foreach (WeekDays day in Enum.GetValues(typeof(WeekDays)))
    {
        Console.WriteLine(day.ToString());
    }
}

//Output

//Sun
//Mon
//Tue
//Wed
//Thu
//Fri
//Sat

Example 7

To represent a combination of choices using an enumeration type, define enum members for each choice as a bit field. This means that the associated values of these enum members should be powers of two. By doing so, you can use the bitwise logical operators | or & to combine choices or intersect combinations of choices, respectively. To indicate that an enumeration type declares bit fields, apply the Flags attribute to it. The following example demonstrates how you can include typical combinations in the definition of an enumeration type.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpTestingArticles
{
    [Flags]
    public enum Days
    {
        None = 0b_0000_0000,  // 0
        Monday = 0b_0000_0001,  // 1
        Tuesday = 0b_0000_0010,  // 2
        Wednesday = 0b_0000_0100,  // 4
        Thursday = 0b_0000_1000,  // 8
        Friday = 0b_0001_0000,  // 16
        Saturday = 0b_0010_0000,  // 32
        Sunday = 0b_0100_0000,  // 64
        Weekend = Saturday | Sunday
    }

    public class FlagsEnumExample
    {
        public static void Main()
        {
            Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
            Console.WriteLine(meetingDays);
            // Output:
            // Monday, Wednesday, Friday

            Days workingFromHomeDays = Days.Thursday | Days.Friday;
            Console.WriteLine($"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
            // Output:
            // Join a meeting by phone on Friday

            bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
            Console.WriteLine($"Is there a meeting on Tuesday: {isMeetingOnTuesday}");
            // Output:
            // Is there a meeting on Tuesday: False

            var a = (Days)37;
            Console.WriteLine(a);
            // Output:
            // Monday, Wednesday, Saturday
        }
    }
}

Example 8

Enum members can be assigned various values. Modifying the default value of an enum member will result in the other members being automatically assigned incremental values in sequence.

public enum ItemsExample
{
    Electronics,    // 0
    Food,           // 1
    Automotive = 6, // 6
    Arts,           // 7
    BeautyCare,     // 8
    Fashion         // 9
}

Example 9

Each member of the enum can be assigned distinct values.

public enum ItemsExample
{
    Electronics = 1,
    Food = 5,
    Automotive = 6,
    Arts = 10,
    BeautyCare = 11,
    Fashion = 15,
    WomanFashion = 15
}

Example 10

In C#, if you want to transform the names of enum values into a string list, you can utilize the Enum.GetNames method. By using this method, you will receive an array of strings that consists of the names of the enum values.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpTestingArticles
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            List<string> enumNames = GetEnumNamesValues<ExampleEnum>();

            foreach (string name in enumNames)
            {
                Console.WriteLine(name);
            }
        }

        public static List<string> GetEnumNamesValues<T>() where T : Enum
        {
            return new List<string>(Enum.GetNames(typeof(T)));
        }
    }

    public enum ExampleEnum
    {
        Value1,
        Value2,
        Value3
    }
}

The GetEnumNames function requires a generic type parameter T that signifies the enum type. It employs Enum.GetNames(typeof(T)) to fetch an array of strings that hold the names of the enum values. This array is then transformed into a string list by utilizing the List<string> constructor. Ultimately, the function provides the list of enum names. GetEnumNames can be invoked with any enum type, resulting in a list of strings that display the names of the enum values.

Example 11

In C#, attributes can be used to add descriptions to enum values. Since C# 7.0, the System.ComponentModel.DescriptionAttribute can be utilized for this purpose.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpTestingArticles
{
    /// <summary>
    /// Interaction logic for DescriptionEnumExample.xaml
    /// </summary>
    public partial class DescriptionEnumExample : Window
    {
        public DescriptionEnumExample()
        {
            InitializeComponent();
            // Access the description of each enum value
            Console.WriteLine(GetDescription(DescriptionEnumClass.Value1)); // Output: first value
            Console.WriteLine(GetDescription(DescriptionEnumClass.Value2)); // Output: second value
            Console.WriteLine(GetDescription(DescriptionEnumClass.Value3)); // Output: third value
        }

        public static string GetDescription(Enum value)
        {
            var field = value.GetType().GetField(value.ToString());
            var attribute = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));
            return attribute == null ? value.ToString() : attribute.Description;
        }
    }
    
    public enum DescriptionEnumClass
    {
        [Description("first value")]
        Value1,
        [Description("second value")]
        Value2,
        [Description("third value")]
        Value3
    }
}

Example 12

Users have the ability to generate a personalized display value for an enum element.

using System.Reflection;
using System.Windows;

namespace WpTestingArticles
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //Retrieve the display name for every enumeration value.
            string name = EnumDisplayNameHelper.GetEnumDisplayName(eEmployeeInfo.Name); // Output: Name of the employee
            string age = EnumDisplayNameHelper.GetEnumDisplayName(eEmployeeInfo.Age); // Output: Age of the employee
        }
    }

    public class CustomEnumDisplayNameAttribute : Attribute
    {
        private string _displayName;
        public string DisplayName
        {
            get { return _displayName; }
            set { _displayName = value; }
        }
    }

    public static class EnumDisplayNameHelper
    {
        public static string GetEnumDisplayName(this Enum value)
        {
            FieldInfo field = value.GetType().GetField(value.ToString());
            CustomEnumDisplayNameAttribute attribute = Attribute.GetCustomAttribute(field, typeof(CustomEnumDisplayNameAttribute)) as CustomEnumDisplayNameAttribute;
            return attribute == null ? value.ToString() : attribute.DisplayName;
        }
    }

    public enum eEmployeeInfo
    {
        [CustomEnumDisplayNameAttribute(DisplayName = "Name of the employee")]
        Name,
        [CustomEnumDisplayNameAttribute(DisplayName = "Age of the employee")]
        Age,
        // Other enum values
    }
}