53

This is a valid enum

public enum myEnum
{
  a= 1,
  b= 2,
  c= 3,
  d= 4,
  e= 5,
  f= 6,
  g= 7,
  h= 0xff
};

But this is not

public enum myEnum
{
  1a = 1,
  2a = 2,
  3a = 3,
};

Is there a way I can use an number in a enum? I already have code that would populate dropdowns from enums so it would be quite handy

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
DrLazer
  • 2,805
  • 3
  • 41
  • 52

8 Answers8

97

No identifier at all in C# may begin with a number (for lexical/parsing reasons). Consider adding a [Description] attribute to your enum values:

public enum myEnum
{
    [Description("1A")]
    OneA = 1,
    [Description("2A")]
    TwoA = 2,
    [Description("3A")]
    ThreeA = 3,
};

Then you can get the description from an enum value like this:

((DescriptionAttribute)Attribute.GetCustomAttribute(
    typeof(myEnum).GetFields(BindingFlags.Public | BindingFlags.Static)
        .Single(x => (myEnum)x.GetValue(null) == enumValue),    
    typeof(DescriptionAttribute))).Description

Based on XSA's comment below, I wanted to expand on how one could make this more readable. Most simply, you could just create a static (extension) method:

public static string GetDescription(this Enum value)
{
    return ((DescriptionAttribute)Attribute.GetCustomAttribute(
        value.GetType().GetFields(BindingFlags.Public | BindingFlags.Static)
            .Single(x => x.GetValue(null).Equals(value)),
        typeof(DescriptionAttribute)))?.Description ?? value.ToString();
}

It's up to you whether you want to make it an extension method, and in the implementation above, I've made it fallback to the enum's normal name if no [DescriptionAttribute] has been provided.

Now you can get the description for an enum value via:

myEnum.OneA.GetDescription()
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • 1
    Nice Solution; but is there an easier way to retreive the description shorter than these 4 lines ? – Xavier Feb 03 '16 at 10:20
  • 1
    Should also point out that it's not limited to `Enum`s, you can use it for anything you apply the `DescriptionAttirbute` to. – will Jun 23 '16 at 15:06
14

No, there isn't. C# does not allow identifiers to start with a digit.

Application usability note: In your application you should not display code identifiers to the end-user anyway. Think of translating individual enumeration items into user-friendly displayable texts. Sooner or later you'll have to extend the enum with an item whose identifier won't be in a form displayable to the user.

UPDATE: Note that the way for attaching displayable texts to enumeration items is being discusses, for example, here.

Community
  • 1
  • 1
Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
  • 2
    You can use DescriptionAttribute to associate a user-friendly string with each enum value and populate your dropdowns by extracting the attribute values instead of showing the raw enums. – John Bowen Oct 12 '10 at 16:45
  • I needed to define an enumeration for printer types that are 58MM and 80MM. These are user friendly displayable texts :P. Nevertheless, solved with _58mm – kuklei Mar 12 '21 at 16:58
10

An identifier in C# (and most languages) cannot start with a digit.

If you can modify the code that populates a dropdown with the enumeration names, you could maybe have a hack that strips off a leading underscore when populating the dropdown and define your enum like so:

public enum myEnum
{
  _1a = 1,
  _2a = 2,
  _3a = 3
};

Or if you don't like the underscores you could come up with your own 'prefix-to-be-stripped' scheme (maybe pass the prefix to the constructor or method that will populate the dropdown from the enum).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
5

Short and crisp 4 line code.

We simply use enums as named integer for items in code,

so any simplest way is good to go.

public enum myEnum
{
    _1 = 1,
    _2,
    _3,
};

Also for decimal values,

public enum myEnum
{
    _1_5 = 1,
    _2_5,
    _3_5,
};

So while using this in code,

int i = cmb1.SelectedIndex(0); // not readable
int i = cmb1.SelectedIndex( (int) myEnum._1_5); // readable
Chandraprakash
  • 773
  • 1
  • 10
  • 18
  • Can you explain how `(int) myEnum._1_5` is more readable than `0`? And to start with, they're not equivalent in your code. It seems like it makes things hard to understand to me. – Enigmativity Jul 01 '21 at 22:37
  • 1
    _1_5 in a remote code can be understood as 1.5, but 0 cannot be understood as 1.5. Thats how – Chandraprakash Jul 03 '21 at 18:58
  • You're saying that you have a number, `1.5`, in an array at position `0`, so the most readable way to access the `1.5` is to do `array[(int)myEnum._1_5]`? That's crazy. If at compile-time you knew you needed `1.5` then `double value = 1.5;` is far better than `double value = array[(int)myEnum._1_5];`. Please tell me in what circumstance this increase in verbosity and indirection make sense? – Enigmativity Jul 04 '21 at 01:57
  • I have a dropdown which has border values for line in PowerPoint which has values like 1, 1.5, 3, 5 etc which I store in enum. So it's easy for me to get/set index based on these value – Chandraprakash Jul 15 '21 at 18:06
  • I think I'd have to see your code to understand why it's useful. – Enigmativity Jul 16 '21 at 01:29
  • In simple words, when you only have choice to select handful of values from dropdown, and here readable in the sense, 0 doesn't say anything, but _1_5 you can understand what value is choosen. – Chandraprakash Aug 07 '21 at 19:15
  • Again, I'd have to see actual code to hopefully understand why this is useful. – Enigmativity Aug 08 '21 at 00:48
4

No way. A valid identifier (ie a valid enumeration member) cannot start with a digit.

Noe
  • 386
  • 1
  • 5
4

Enumerations are no different than variables in terms of naming rules. Therefore, you can't start the name with a number. From this post, here are the main rules for variable naming.

  • The name can contain letters, digits, and the underscore character (_).

    • The first character of the name must be a letter. The underscore is also a legal first character, but its use is not recommended at the beginning of a name. An underscore is often used with special commands, and it's sometimes hard to read.

    • Case matters (that is, upper- and lowercase letters). C# is case-sensitive; thus, the names count and Count refer to two different variables.

    • C# keywords can't be used as variable names. Recall that a keyword is a word that is part of the C# language. (A complete list of the C# keywords can be found in Appendix B, "C# Keywords.")

keyboardP
  • 68,824
  • 13
  • 156
  • 205
  • 4
    Better yet, the C# Language Specification section on Identifiers: http://msdn.microsoft.com/en-us/library/aa664670(v=VS.71).aspx – Jim Mischel Oct 12 '10 at 16:37
4

Identifiers can't start with numbers. However, they can contain numbers.

Rohan Singh
  • 20,497
  • 1
  • 41
  • 48
-3

Here is what i came up with as an alternative, where I needed Enums to use in a "for" Loop and a string representation equivalent to use in a Linq query.

  1. Create enums namespace to be used in "for" Loop.
public enum TrayLevelCodes
    {
        None,
        _5DGS,
        _5DG,
        _3DGS,
        _3DG,
        _AADC,
        _ADC,
        _MAAD,
        _MADC
    };
  1. Create strings based on enum created to be used for Linq query
public string _5DGS = "\"5DGS\"",
        _5DG = "\"5DG\"",
        _3DGS = "\"3DGS\"",
        _3DG = "\"3DG\"",
        _AADC = "\"AADC\"",
        _ADC = "\"ADC\"",
        _MAAD = "\"MAAD\"",
        _MADC = "\"MADC\"";
  1. Create function that will take an enum value as argument and return corresponding string for Linq query.
public string GetCntnrLvlDscptn(TrayLevelCodes enumCode)
        {
            string sCode = "";
            switch (enumCode)
            {
                case TrayLevelCodes._5DGS:
                    sCode = "\"5DGS\"";
                    break;
                case TrayLevelCodes._5DG:
                    sCode = "\"5DG\"";
                    break;
                case TrayLevelCodes._3DGS:
                    sCode = "\"3DGS\"";
                    break;
                case TrayLevelCodes._3DG:
                    sCode = "\"3DG\"";
                    break;
                case TrayLevelCodes._AADC:
                    sCode = "\"AADC\"";
                    break;
                case TrayLevelCodes._ADC:
                    sCode = "\"AAC\"";
                    break;
                case TrayLevelCodes._MAAD:
                    sCode = "\"MAAD\"";
                    break;
                case TrayLevelCodes._MADC:
                    sCode = "\"MADC\"";
                    break;
                default:
                    sCode = "";
                    break;
            }
                return sCode;
        }
  1. Here is how i am using what i created above.
for (var trayLevelCode = TrayLevelCodes._5DGS; trayLevelCode <= TrayLevelCodes._MADC; trayLevelCode++)
{
    var TrayLvLst = (from i in pair1.Value.AutoMap
                     where (i.TrayLevelCode == HTMLINFO.GetCntnrLvlDscptn(trayLevelCode))
                     orderby i.TrayZip, i.GroupZip
                     group i by i.TrayZip into subTrayLvl
                     select subTrayLvl).ToList();
    foreach (DropShipRecord tray in TrayLvLst)
    {

    }
}
Nerdroid
  • 13,398
  • 5
  • 58
  • 69