Search code examples
c#xmlenumsrefactoringautomated-refactoring

An easy way to refactor Enums to include numeric value?


I`ve got a bunch of Enums that have been generated from an XSD. They have formats like the following (enums with names, but not numeric values):

public enum MyEnum
{        
    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("001")]
    Item001,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("002")]
    Item002,

    .... // etc.

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("199")]
    Item199,
}

What I would like is a simple way to refactor these as follows:

public enum MyEnum
{ 
    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("001")]
    Item001 = 1,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("002")]
    Item002 = 2,

    .... // etc.

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("199")]
    Item199 = 199,
}

I need this in order to parse integer values (from a config-file or a DB) into enum values. Note that the needed int values are found both in the XmlEnumAttribute, and in the enum value name itself - just not as a numeric value.

Any ideas for performing this refactoring quickly would be greatly appreciated.

Example and extra background info:

I want to do:

var myEnumValue = (MyEnum) integerFromDb;

I realize that I could probably solve this by creating a method that appends the int value of each piece of data to the string Item, and parses it to an enum using the resulting name, but that has a couple of weaknesses:

  • Feels like a dirty hack
  • Might not work properly for names like MyEnum.Item02 and MyOtherEnum.Item002
  • It would not allow me to refer to enum values using the integer values that are defined outside my system (i.e. this would not be in proper compliance with the rules in the XSD that my enums are based on).

Solution

  • You can use Visual Studio's search-and-replace feature to do this without too much trouble (note…I am assuming VS2013 here, which uses the standard .NET regex syntax; earlier versions of VS can do this also, but they use a custom regex syntax, which you can look up yourself if needed):

    1. Open your source file. Make sure every enum value is declared identically; in particular, put a comma after even the last one.
    2. Press Ctrl+H to show the search-and-replace UI
    3. Enter Item(\d+), as your text to find, and Item$1 = $1, as the replacement text.
    4. Make sure the scope is set to "Current Document".
    5. Press Alt+A. This will replace all matches in the file.

    This actually is enough to get the code to compile as you want. But you may prefer to remove leading 0 digits. You can again use the search-and-replace to do that:

    1. Enter = 0 as the text to find, and = as the replacement text.
    2. Press Alt+A twice (because you have at most two leading zeroes)

    Finally: as far as your idea of handling it in run-time only, converting via the value name would indeed be potentially problematic, given the dependency on the exact formatting of the name. But note that you have a true parseable integer here, in the [XmlEnum] attribute.

    So if you wanted to create the necessary dictionaries for converting (you wouldn't want to keep inspecting the attribute itself, as reflection is slow), you could enumerate the enum type via reflection, get the attributes for each value, parse the string found in the XmlEnumAttribute.Name property, and use that to create dictionary entries, i.e. in a Dictionary<int, MyEnum> and Dictionary<MyEnum, int> to facilitate conversion in either direction.