locked
[?] Enum and string constants

    Question

  • Hello, experts

    I have some string constants, and I don't know how will be better to organize it in the code... It will be nice to use enums, but I have a little problem cause of special symbols:
    <columns> 
      <trailer-status/> 
      <current-load-id /> 
      <trailer-prefix /> 
      <trailer-number /> 
      <equipment-type /> 
      <trailer-hold-flags /> 
      <trailer-grade /> 
      <previous-load-id /> 
      <move-destination-date-time /> 
      <release-date-time /> 
      <per-diem-last-free-day /> 
      <ready-begin-date /> 
      <ready-begin-time /> 
      <ready-end-date /> 
      <ready-end-time /> 
      <ready-note /> 
      <car-owner /> 
      <move-chassis-prefix /> 
      <move-chassis-number /> 
      <allocation-customer /> 
      <allocation-customer-name /> 
      <current-location /> 
      <current-location-name /> 
    </columns> 
    well, any ideea how to keep it in enum?

    Or it will be better using traditional const string[] collection...

    thanks

    there are some approaches, like
    public enum States
    {
    California,
    [Description("New Mexico")]
    NewMexico,
    [Description("New York")]
    NewYork,
    [Description("South Carolina")]
    SouthCarolina,
    Tennessee,
    Washington
    }

    but I find it very expensive, using refactoring....

    now, probably something like:

            public enum DeadNumbers

            {

                one = "o-n-e",

                two = "t.wo"

            }

    will pass?

    Best regards, Sergiu
    • Edited by Sergiu Dudnic Monday, June 30, 2008 4:12 PM completed
    Monday, June 30, 2008 4:05 PM

Answers

  • Thanks massdriver.  I always overlook those static functions.  I only discovered string.Join a few days ago!

    Sergiu,  The following would allow you to get an enum member from a string.  Is that what you mean?

    using System; 
    using System.Text.RegularExpressions; 
     
    namespace Green 
        class Grass 
        { 
            public enum Columns 
            { 
                one = 20, 
                A_20B_20C = 25, 
                trailer_2Dstatus_2Eone = 30, 
                cab_5Fprefix = 35, 
                Oh_21_20_22_29_2A_26_26_25_26_29_5F_2A_5F_21_21_21_22 = 40 
            } 
     
            static readonly string[] names = new string[] { "one""A B C""trailer-status.one""cab_prefix""Oh! \")*&&%&)_*_!!!\"" }; 
            static void Main(string[] args) 
            { 
                Type t = typeof(Columns); 
                foreach (string name in names) 
                { 
                    Columns column = (Columns)Enum.Parse(t, EnumEncode(name)); 
                    Console.WriteLine(((int)column).ToString() + ": " + column.ToString() + " / " + name); 
                } 
                Console.ReadLine();  
            } 
     
            static string EnumEncode(string text) 
            { 
                return Regex.Replace(text, @"[^\da-zA-Z]", m => "_" + ((int)m.Value[0]).ToString("x0").ToUpper() ); 
            } 
        } 

    Output:
    20: one / one
    25: A_20B_20C / A B C
    30: trailer_2Dstatus_2Eone / trailer-status.one
    35: cab_5Fprefix / cab_prefix
    40: Oh_21_20_22_29_2A_26_26_25_26_29_5F_2A_5F_21_21_21_22 / Oh! ")*&&%&)_*_!!!"

    Good luck,

    John
    Tuesday, July 01, 2008 7:33 PM

All replies

  • Hi Sergiu,

    I've posted some code below that shows 3 different ways of doing what I think you want.   1) uses enum, 2) uses string constants, 3) uses a custom class.

    It's very hard to say which, if any, is 'right'.  As you say you could also use an array and  I imagine there are dozens of other solutions.

    Here are some of the factors I might consider.

    Do I need to be able enumerate (e.g. foreach) over the data?
    At some point might I want to modify the list programatically?
    Do I really need to make it type safe?
    Might I want to add extra properties later?
    Might I want multi-lingual support at some point?

    What I might end up doing is doing what's simplest (e.g. store the strings in an array) but then access the array via a Method like "GetColumNames".  Then if I change the implementation in the future I only need to change it one place.

    Good luck,

    John
    using System; 
    using System.Collections.Generic; 
     
    namespace Green 
     
        class Program 
        { 
            static void Main(string[] args) 
            { 
                Console.WriteLine("1) Using Enum:"); 
                DisplayEnum(Columns.current_load_id); 
                DisplayEnum(Columns.trailer_prefix); 
                DisplayEnum(Columns.trailer_status);   
                //DisplayEnum("poor");  This line won't compile 
                Console.WriteLine(); 
     
                Console.WriteLine("2) Using Constant Strings:");            
                Console.WriteLine(States.NewMexico); 
                Console.WriteLine(States.NewYork); 
                Console.WriteLine(States.SouthCarolina); 
                Console.WriteLine("poor"); // This does compile !! 
                Console.WriteLine(); 
     
                Console.WriteLine("3a) Using a Custom Class:");             
                DisplayCustomState(CustomState.NewMexico); 
                DisplayCustomState(CustomState.NewYork); 
                DisplayCustomState(CustomState.SouthCarolina); 
                //DisplayCustomState("poor"); This line won't compile; 
                Console.WriteLine(); 
     
                Console.WriteLine("3b) Enumerating over the Custom Class:");             
                foreach (CustomState state in CustomState.AllStates) 
                    DisplayCustomState(state); 
                Console.WriteLine(); 
     
                Console.WriteLine("4) Using an Array:"); 
                foreach (string state in GetStateNames()) 
                    Console.WriteLine(state); ; 
     
                Console.ReadLine(); 
            } 
     
            static void DisplayEnum(Columns column) 
            { 
                Console.WriteLine(column.ToString().Replace('_', '-')); 
            } 
     
            static void DisplayConstant(string stateName) 
            { 
                Console.WriteLine(stateName); 
            } 
     
            static void DisplayCustomState(CustomState state){ 
                Console.WriteLine(state.DispalayName); 
            } 
     
     
     
            static string[] stateArray = new string[] { "New York""New Jersey""New Hampshire" }; 
            static IEnumerable<string> GetStateNames() 
            { 
                return stateArray; 
                /// In the future I might go off and get his list from a database or webservice 
            } 
     
        } 
     
        // enum 
        public enum Columns 
        { 
            trailer_status, 
            current_load_id, 
            trailer_prefix, 
        } 
     
     
        // constants 
        static class States 
        { 
            public const string California = "California"
            public const string NewYork = "New York"
            public const string NewMexico = "New Mexico"
            public const string SouthCarolina = "South Carolina"
        } 
     
        // custom class 
        class CustomState{ 
     
            static List<CustomState> allStates = new List<CustomState>(); 
     
            CustomState(string displayName){ 
                DispalayName = displayName; 
                allStates.Add(this); 
            } 
     
            public string DispalayName { getprotected set; } 
     
            public override string ToString() 
            { 
                return DispalayName; 
            } 
     
            public static IEnumerable<CustomState> AllStates 
            { 
                get { return allStates; } 
            } 
     
            public static readonly CustomState California = new CustomState("California"); 
            public static readonly CustomState NewYork = new CustomState("New York"); 
            public static readonly CustomState NewMexico = new CustomState("New Mexico"); 
            public static readonly CustomState SouthCarolina = new CustomState("South Carolina"); 
     
        } 
     
     
    Output:
    1) Using Enum:
    current-load-id
    trailer-prefix
    trailer-status

    2) Using Constant Strings:
    New Mexico
    New York
    South Carolina
    poor

    3a) Using a Custom Class:
    New Mexico
    New York
    South Carolina

    3b) Enumerating over the Custom Class:
    California
    New York
    New Mexico
    South Carolina

    4) Using an Array:
    New York
    New Jersey
    New Hampshire

    Monday, June 30, 2008 6:41 PM
  • Very good John! Just wanted to bring some attention to the fact that all underscore characters in code becomes spaces... Wonder when they will fix this?
    /Calle
    Monday, June 30, 2008 6:46 PM
  • They're not actually converted to spaces.  If you copy the code and paste into notepad the underscores are there.  They just don't show up in code blocks.  I also wonder when they will fix this.
    Monday, June 30, 2008 10:37 PM
  • Correct, its the row height that's to narrow to show the underscores.
    Monday, June 30, 2008 10:44 PM
  • I was a little confused by your comment because I can see the underscores.

    You probably knew this, but after a little experiment it looks like the problem is, at least in part, a browser issue as I'm using Firefox.  In Firefox and Safari the underscores look fine to me, in IE they dissappear.

    So... I expect it'll be fixed no later than the release IE 8 :-)

    Cheers,

    John
    Tuesday, July 01, 2008 3:12 AM
  • thanks rtizan[0]

    for you solution.

    However, there appears some difficulties when we have different type of non-standard string at once, by eg. "trailer-status.one".
    An other problem is that
    //DisplayEnum("poor");  This line won't compile
    I should write some special functions for comparing text "myEnumCandidate..." with enum.ToString().

    Also I couldn't use foreach for "enum Columns" to display all the items...

    Best regards, Sergiu
    Tuesday, July 01, 2008 1:09 PM
  • Hi Sergiu,

    You're absolutely right, if there's more than one non-alphanumeric character you want to display then my solution that uses enum won't work. 

    The "This line doesn't compile" comment is pointing out that enum and the customClass are type safe.  I.e. if a variable is of type 'States' then you can only assign a defined state to it.  If you try assign an arbitrary string then you will be warned at compile time time that youre breaking your rules.

    Personally I don't think enum is the right choice for containing display strings.  What solution I would try would depend on my requirements (Do I want to be able to enumerate, etc...).

    I Expect that in the two expamples we're talking about I would probably create custom classes for State and ColumnInfo so that at some future date if I wanted to store extra info such as the State's abbreviation (NY, NJ, CA, ..) or a Column's width I could just add that extra property to the existing classes.

    Good luck,

    John


    Tuesday, July 01, 2008 2:50 PM
  • I must have too much time to spare today.  I got to wondering how one could use an enum to store an (almost) arbitrary string, and how one would enumerate over it.  It ain't pretty...

    using System; 
    using System.Reflection; 
    using System.Text.RegularExpressions; 
     
    namespace Green 
        class Grass 
        { 
            public enum Columns 
            { 
                trailer_status, 
                current_load_id, 
                trailer_prefix, 
                A_20BIG_21_20trailer_2Dstatus_2Eone 
            } 
     
            static readonly Regex asciiCodes = new Regex(@"_[\dA-F]{2}", RegexOptions.Compiled | RegexOptions.ExplicitCapture); 
            static readonly Func<stringstring> getStringFromAsciiCode =  
                code => ((char)int.Parse(code, System.Globalization.NumberStyles.AllowHexSpecifier)).ToString(); 
     
            static void Main(string[] args) 
            { 
                foreach (MemberInfo member in typeof(Columns).GetFields(BindingFlags.Public | BindingFlags.Static)) 
                    Console.WriteLine(asciiCodes.Replace(member.Name, match => getStringFromAsciiCode(match.Value.Substring(1)))); 
                Console.ReadLine(); 
           } 
        } 

    Output:
    trailer_status
    current_load_id
    trailer_prefix
    A BIG! trailer-status.one
    Tuesday, July 01, 2008 3:40 PM
  • my God.... :)

    ... there should be are also the enum from string comparator, in order that you could take an enum from the string...

    Best regards, Sergiu
    Tuesday, July 01, 2008 5:47 PM
  • Instead of this:

    foreach (MemberInfo member in typeof(Columns).GetFields(BindingFlags.Public | BindingFlags.Static)) 

    Enum has a built-in enumerator:

    foreach (var item in Enum.GetNames(typeof(Columns)))  
    {  
        Console.WriteLine(asciiCodes.Replace(item, match => getStringFromAsciiCode(match.Value.Substring(1))));  
    Tuesday, July 01, 2008 6:02 PM
  • Thanks massdriver.  I always overlook those static functions.  I only discovered string.Join a few days ago!

    Sergiu,  The following would allow you to get an enum member from a string.  Is that what you mean?

    using System; 
    using System.Text.RegularExpressions; 
     
    namespace Green 
        class Grass 
        { 
            public enum Columns 
            { 
                one = 20, 
                A_20B_20C = 25, 
                trailer_2Dstatus_2Eone = 30, 
                cab_5Fprefix = 35, 
                Oh_21_20_22_29_2A_26_26_25_26_29_5F_2A_5F_21_21_21_22 = 40 
            } 
     
            static readonly string[] names = new string[] { "one""A B C""trailer-status.one""cab_prefix""Oh! \")*&&%&)_*_!!!\"" }; 
            static void Main(string[] args) 
            { 
                Type t = typeof(Columns); 
                foreach (string name in names) 
                { 
                    Columns column = (Columns)Enum.Parse(t, EnumEncode(name)); 
                    Console.WriteLine(((int)column).ToString() + ": " + column.ToString() + " / " + name); 
                } 
                Console.ReadLine();  
            } 
     
            static string EnumEncode(string text) 
            { 
                return Regex.Replace(text, @"[^\da-zA-Z]", m => "_" + ((int)m.Value[0]).ToString("x0").ToUpper() ); 
            } 
        } 

    Output:
    20: one / one
    25: A_20B_20C / A B C
    30: trailer_2Dstatus_2Eone / trailer-status.one
    35: cab_5Fprefix / cab_prefix
    40: Oh_21_20_22_29_2A_26_26_25_26_29_5F_2A_5F_21_21_21_22 / Oh! ")*&&%&)_*_!!!"

    Good luck,

    John
    Tuesday, July 01, 2008 7:33 PM
  • heh, I already see this enum in code:
    if (myvar == Oh_21_20_22_29_2A_26_26_25_26_29_5F_2A_5F_21_21_21_22)
    :)

    Best regards, Sergiu
    Thursday, July 03, 2008 9:35 AM