Adding display name to Enum values
Image from Unsplash

Adding display name to Enum values

Implementing additional values for Enum items in C#

Enums are great way do list available options for certain variable values in your code. However, they do not come without limitations and they are not suitable for all scenarios.

One of those limitations are Enum value names which have restrictions similar to variable name restrictions in C#. One of the most annoying ones is that you cannot use spaces or certain special characters for Enum value name. This makes enum values less usable to directly display in the UI especially if your application does not support multiple languages and you do not have dictionary somewhere for each value.

Let me simplify this by showing a simple example application where we just want to display human friendly values of the power supply type.

        public enum PowerSupplyType
        {
            AC,
            DC
        }

        static void Main(string[] args)
        {
            var powerSupplyType = PowerSupplyType.AC;

            switch (powerSupplyType)
            {
                case PowerSupplyType.AC:
                    Console.WriteLine("Alternating Current");
                    break;
                case PowerSupplyType.DC:
                    Console.WriteLine("Direct Current");
                    break;
                default:
                    Console.WriteLine("Unknown");
                    break;
            }

            Console.ReadKey();
        }
    

Here we have a simple enum which only contains two values which names are abbreviation for alternating/direct current. We want to use abbreviation values in our code to assign values to variables like we do, but we would still like to display to end user full name not just abbreviation.

For that purpose we had to introduce a switch statement. There is nothing wrong with using switch statement, but imagine you need to introduce new value to this enum. You would have to also change your switch statement to handle this new value, otherwise your console will always display "Unknown" text.

Maybe this is not so obvious in this super simple scenario, but It's a fact that you have additional place where you need to add special handling and this is potential place where bug may occur.

To overcome this, I will use System.ComponentModel.DataAnnotations.DisplayAttribute to decorate each Enum value with additional value and use reflection to read it.

    class Program
    {
       public enum PowerSupplyType
        {
            [Display(Name = "Alternating Current")]
            AC,
            [Display(Name = "Direct Current")]
            DC
        }

        static void Main(string[] args)
        {
            var powerSupplyType = PowerSupplyType.AC;

            var names = typeof(PowerSupplyType).GetFields(BindingFlags.Public | BindingFlags.Static)
                .Select(f => f.GetCustomAttribute<DisplayAttribute>()?.Name ?? f.Name);
            var values = Enum.GetValues(typeof(PowerSupplyType)).Cast<int>();

            var dictionary = names.Zip(values, (n, v) => new KeyValuePair<int, string>(v, n))
                .ToDictionary(kv => kv.Key, kv => kv.Value);

            Console.WriteLine(dictionary[(int)powerSupplyType]);

            Console.ReadKey();
        }
    }
    

In addition, for values that are not decorated with DisplayAttribute enum value name will be taken and assigned to enum value in the final dictionary. This was we are not making this attribute mandatory and we do not have to add it for value that are fine to be displayed in the UI.

As much as we got rid of the switch statement and we are handling new values out of the box, this code as it is now is not much reusable, so let's refactor for more re-usability.

Since I may want to have an extension method for other enums, whole display value calculation is taken out to a private method GetEnumValueNames which produces a dictionary where key is enum value number and value is enum name or DisplayAttribute of that enum element if present.

    public enum PowerSupplyType
    {
        [Display(Name = "Alternating Current")]
        AC,
        [Display(Name = "Direct Current")]
        DC
    }

    public static class EnumExtensions
    {
        static IDictionary<int, String> GetEnumValueNames(Type type)
        {
            var names = type.GetFields(BindingFlags.Public | BindingFlags.Static)
                .Select(f => f.GetCustomAttribute<DisplayAttribute>()?.Name ?? f.Name);

            var values = Enum.GetValues(type).Cast<int>();

            var dictionary = names.Zip(values, (n, v) => new KeyValuePair<int, string>(v, n))
                .ToDictionary(kv => kv.Key, kv => kv.Value);

            return dictionary;
        }

        public static String GetDisplayName(this PowerSupplyType value)
        {
            var dictionary = GetEnumValueNames(value.GetType());
            return dictionary[(int)value];
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var powerSupplyType = PowerSupplyType.AC;
            Console.WriteLine(powerSupplyType.GetDisplayName());

            Console.ReadKey();
        }
    }
    

This way, we can get our display name from enum value just by simply calling GetDisplayName for the enum value we have assigned to variable in our main logic without having to bother how will it be acquired.

All we would have to do to support another enum is to create an extension method almost the same as GetDisplayName where we are going to reference different enum type we want to have extension applied to. 

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform including ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article