3

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).
Kjartan
  • 18,591
  • 15
  • 71
  • 96

2 Answers2

3

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.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thanks Peter, that is a great answer, and exactly what I was looking for. I'd replaced the some of the most important and frequently used enums by hand by now, but I still had some very lengthy ones left. You've saved me a lot of work. – Kjartan Jan 13 '15 at 06:55
2

I've already accepted the answer by Peter Duniho, but would like to expand a little more on it here, since I used a couple of variations:

In my generated file, most of the enums were in the same file, and for some of them, then values had already been replaced. Running the "Replace All" procecure would therefore cause other problems.

Replace next
Therefore, instead of Alt + A (replace all) to replace all matches, I used Alt + R (replace next) repeatedly to loop through and replace only those matches necessary. This let me quickly loop through all my code, without messing up what was already fixed.

F3 (Find Next) can be used as in a normal search, to skip matches that should not be altered.

Leading zeros
I didn't want to remover the 0 in e.g. Item010 = 0, which would be invalid, so I used the following search term instead: = 0\d, which finds only leading zeros (i.e. zeros followed by another number).

Community
  • 1
  • 1
Kjartan
  • 18,591
  • 15
  • 71
  • 96