Udostępnij za pośrednictwem


The Enum changed to int: How do you convert the int back to a name?

I wrote a tool that loaded some binary data and displayed it in a nice form, where the user could browse the data, sort by various columns, filter, export, etc.

The tool relied on the fact that a column of the data contained an integer ID indicating the type of item.

For our purposes, let’s say that column was the name of a City. Seattle could be 1, Boston=2, etc.

There were thousands of items, as there are thousands of Cities. The binary data stored the integer, and the tool translated that number to the City name.

This was pretty easy, because I had the source code that generated the binary data, and the integer was an Enum, so I just added the file defining the Enum type to my project.

Months later, somebody found a reason to change the type from an Enum to an integer. (The reasons had something to do with accessing the data from VB, C# and C++, and making it easier to update the data with minimal fuss.)

This broke my tool, which fell back to just displaying integers.

How do we fix this?

Below is sample code that contains both the original Enum format (CityDataEnum) for the data and the newer integer format (CityDataInt).

Start Visual Studio, File->New Project->C#->WPF Application

Replace MainWindow.xaml.cs with the code below

Hit F10 to build and step into the code and observe the data and the types in the Locals Window.

The solution was to write a simple class that had a static method “IdToString”.

The first time called, it builds a Dictionary with a key being the Integer and the name obtained by using Reflection

Then it just looks up the name in the dictionary.

<Code>

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;

namespace WpfApplication1
{
    // Storing constants as enums is easy
    // Enums are nice to work with: 
    // You can convert from the name to the value easily
    // You can also get the name as a string easily
    // Imagine thousands of cities, each being an enum value.
    public enum CityDataEnum
    {
        Seattle = 1,
        Boston = 2,
        London = 3
    }

    // storing constants as integers is also easy,
    // but it's not so easy to get the name of the constant
    // There were thousands of Enums, and someone 
    // found a legitimate reason to convert them
    // to integers <sigh>
    public static class CityDataInt
    {
        public const int Seattle = 1;
        public const int Boston = 2;
        public const int London = 3;
    }
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // it's easy to use the Enums.
            var valEnum = CityDataEnum.Boston;
            // Locals window shows Boston, but the type is not string:
            // the Type is; WpfApplication1.CityDataEnum

            if ((int)valEnum == 2) // this evaluates to true: Boston == 2
            {
                Debug.WriteLine("this is executed ebcause valEnum == Boston");
            }
            // now get the string value of the Enum
            var valEnumString = valEnum.ToString();
            // The type of valEnumString is now String 
            // and the value is the string "Boston"
            // You write a tool that displays the data nicely, 
            // replacing 1 with "Seattle" easily, 
            // making it easy to read the data.

            // now ship your code and everybody's happy




            // Months later, after somebody changes the Enums to ints
            // lets try using the Ints.
            var valClassData = CityDataInt.Seattle;
            // the Locals window shows this is an int = 1. 
            // how do we get the name of the int 
            // as a string as we did with the enum ?

            // Here's one way: by using a class:
            var valClassDataString = ClassDataHandler.IdToString(valClassData + 10);
            // now the Locals window shows the type is String = "Seattle" !

        }
    }

    public class ClassDataHandler
    {
        // we'll keep a single static dictionary mapping the ID to the name, 
        // containing the name and the enumVal for that name
        internal static Dictionary<int, string> _dictValues;
        public static string IdToString(int dataId)
        {
            // need to convert from const int to the member name
            // check to see if we've initialized yet
            if (_dictValues == null)
            {
                // initialize by creating a list once.
                _dictValues = new Dictionary<int, string>();
                var fields = typeof(CityDataInt).GetFields();
                foreach (var field in fields)
                {
                    _dictValues[(int)field.GetValue(null)] = field.Name;
                }
            }
            if (!_dictValues.ContainsKey(dataId))
            {
                throw new InvalidOperationException("ID not found");
            }
            return _dictValues[dataId];
        }
    }

}

</Code>