C# Iterating through an enum? (Indexing a System.Array)
Asked Answered
S

13

136

I have the following code:

// Obtain the string names of all the elements within myEnum 
String[] names = Enum.GetNames( typeof( myEnum ) );

// Obtain the values of all the elements within myEnum 
Array values = Enum.GetValues( typeof( myEnum ) );

// Print the names and values to file
for ( int i = 0; i < names.Length; i++ )
{
    print( names[i], values[i] ); 
}

However, I cannot index values. Is there an easier way to do this?

Or have I missed something entirely!

Suburbanize answered 27/1, 2009 at 9:11 Comment(0)
R
235
Array values = Enum.GetValues(typeof(myEnum));

foreach( MyEnum val in values )
{
   Console.WriteLine (String.Format("{0}: {1}", Enum.GetName(typeof(MyEnum), val), val));
}

Or, you can cast the System.Array that is returned:

string[] names = Enum.GetNames(typeof(MyEnum));
MyEnum[] values = (MyEnum[])Enum.GetValues(typeof(MyEnum));

for( int i = 0; i < names.Length; i++ )
{
    print(names[i], values[i]);
}

But, can you be sure that GetValues returns the values in the same order as GetNames returns the names ?

Reducer answered 27/1, 2009 at 9:16 Comment(6)
"But, can you be sure that GetValues returns the values in the same order as GetNames returns the names ?" -- This is a very good point and something I have yet to address! I think your first solution would probably provide a way to match values and strings reliablySuburbanize
Hello, I've seen mention before of this suspicion of "index-mismatching" occurring when doing this; however, I've yet to discover whether this really is a concern or not? Are there any definitive cases whereby this assumption may go awry? Thx!Extremadura
You probably want to cast the second "val" to an int, if you want to troubleshoot value mismatch as in Enum.GetName(typeof(MyEnum), val), (int)val) in which the output provides the enumeration name and number.Griseous
GetValues and GetNames return in the same order, namely: "The elements of the return value array are sorted by the binary values of the enumerated constants (that is, by their unsigned magnitude)."Retiarius
I believe you can also use LINQ directly by calling Cast<T> on the result: Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...Empennage
Correct me if i am wrong, don't we need to parse the value to respective type before printing it. (int)val something like this when value type is int?Encipher
C
36

You need to cast the array - the returned array is actually of the requested type, i.e. myEnum[] if you ask for typeof(myEnum):

myEnum[] values = (myEnum[]) Enum.GetValues(typeof(myEnum));

Then values[0] etc

Crossbar answered 27/1, 2009 at 9:17 Comment(0)
R
10

You can cast that Array to different types of Arrays:

myEnum[] values = (myEnum[])Enum.GetValues(typeof(myEnum));

or if you want the integer values:

int[] values = (int[])Enum.GetValues(typeof(myEnum));

You can iterate those casted arrays of course :)

Rodriguez answered 27/1, 2009 at 9:21 Comment(0)
S
8

How about a dictionary list?

Dictionary<string, int> list = new Dictionary<string, int>();
foreach( var item in Enum.GetNames(typeof(MyEnum)) )
{
    list.Add(item, (int)Enum.Parse(typeof(MyEnum), item));
}

and of course you can change the dictionary value type to whatever your enum values are.

Scalade answered 27/1, 2009 at 9:25 Comment(2)
I think that this would be the way to go, but unfortucatly the enum is in an area of code which I have no control over!Suburbanize
The only solution I've found that gets the actual integer enum values!Leftist
H
4

What about using a foreach loop, maybe you could work with that?

  int i = 0;
  foreach (var o in values)
  {
    print(names[i], o);
    i++;
  }

something like that perhaps?

Hotfoot answered 27/1, 2009 at 9:15 Comment(2)
I have thaught of that ... but I need to get access to both names and values in 'sync' ... say the names[2] is paired with values[2] and I am unsure as to how to achieve this in a foreach loop!Suburbanize
I've added an example - see if that helps.Hotfoot
M
4

Here is another. We had a need to provide friendly names for our EnumValues. We used the System.ComponentModel.DescriptionAttribute to show a custom string value for each enum value.

public static class StaticClass
{
    public static string GetEnumDescription(Enum currentEnum)
    {
        string description = String.Empty;
        DescriptionAttribute da;

        FieldInfo fi = currentEnum.GetType().
                    GetField(currentEnum.ToString());
        da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi,
                    typeof(DescriptionAttribute));
        if (da != null)
            description = da.Description;
        else
            description = currentEnum.ToString();

        return description;
    }

    public static List<string> GetEnumFormattedNames<TEnum>()
    {
        var enumType = typeof(TEnum);
        if (enumType == typeof(Enum))
            throw new ArgumentException("typeof(TEnum) == System.Enum", "TEnum");

        if (!(enumType.IsEnum))
            throw new ArgumentException(String.Format("typeof({0}).IsEnum == false", enumType), "TEnum");

        List<string> formattedNames = new List<string>();
        var list = Enum.GetValues(enumType).OfType<TEnum>().ToList<TEnum>();

        foreach (TEnum item in list)
        {
            formattedNames.Add(GetEnumDescription(item as Enum));
        }

        return formattedNames;
    }
}

In Use

 public enum TestEnum
 { 
        [Description("Something 1")]
        Dr = 0,
        [Description("Something 2")]
        Mr = 1
 }



    static void Main(string[] args)
    {

        var vals = StaticClass.GetEnumFormattedNames<TestEnum>();
    }

This will end returning "Something 1", "Something 2"

Motherly answered 4/1, 2010 at 23:44 Comment(1)
Only good if the descriptions are static... if your descriptions need to change based on an instance basis then this approach won't work.Pagano
I
4

Another solution, with interesting possibilities:

enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

static class Helpers
{
public static IEnumerable<Days> AllDays(Days First)
{
  if (First == Days.Monday)
  {
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
     yield return Days.Saturday;
     yield return Days.Sunday;
  } 

  if (First == Days.Saturday)
  {
     yield return Days.Saturday;
     yield return Days.Sunday;
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
  } 
}
Instruction answered 3/10, 2011 at 7:43 Comment(0)
H
4

Old question, but a slightly cleaner approach using LINQ's .Cast<>()

var values = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();

foreach(var val in values)
{
    Console.WriteLine("Member: {0}",val.ToString());     
}
Hasan answered 7/5, 2013 at 16:23 Comment(0)
O
4

In the Enum.GetValues results, casting to int produces the numeric value. Using ToString() produces the friendly name. No other calls to Enum.GetName are needed.

public enum MyEnum
{
    FirstWord,
    SecondWord,
    Another = 5
};

// later in some method  

 StringBuilder sb = new StringBuilder();
 foreach (var val in Enum.GetValues(typeof(MyEnum))) {
   int numberValue = (int)val;
   string friendyName = val.ToString();
   sb.Append("Enum number " + numberValue + " has the name " + friendyName + "\n");
 }
 File.WriteAllText(@"C:\temp\myfile.txt", sb.ToString());

 // Produces the output file contents:
 /*
 Enum number 0 has the name FirstWord
 Enum number 1 has the name SecondWord
 Enum number 5 has the name Another
 */
Oystercatcher answered 30/6, 2016 at 18:43 Comment(0)
P
2

Array has a GetValue(Int32) method which you can use to retrieve the value at a specified index.

Array.GetValue

Polygnotus answered 27/1, 2009 at 9:35 Comment(0)
M
2

You can simplify this using format strings. I use the following snippet in usage messages:

writer.WriteLine("Exit codes are a combination of the following:");
foreach (ExitCodes value in Enum.GetValues(typeof(ExitCodes)))
{
    writer.WriteLine("   {0,4:D}: {0:G}", value);
}

The D format specifier formats the enum value as a decimal. There's also an X specifier that gives hexadecimal output.

The G specifier formats an enum as a string. If the Flags attribute is applied to the enum then combined values are supported as well. There's an F specifier that acts as if Flags is always present.

See Enum.Format().

Magill answered 12/10, 2012 at 17:0 Comment(0)
E
0

Here is a simple way to iterate through your custom Enum object

For Each enumValue As Integer In [Enum].GetValues(GetType(MyEnum))

     Print([Enum].GetName(GetType(MyEnum), enumValue).ToString)

Next
Ebullition answered 11/9, 2009 at 21:27 Comment(0)
G
0

Ancient question, but 3Dave's answer supplied the easiest approach. I needed a little helper method to generate a Sql script to decode an enum value in the database for debugging. It worked great:

    public static string EnumToCheater<T>() {
        var sql = "";
        foreach (var enumValue in Enum.GetValues(typeof(T)))
            sql += $@"when {(int) enumValue} then '{enumValue}' ";
        return $@"case ?? {sql}else '??' end,";
    }

I have it in a static method, so usage is:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Gabie answered 1/8, 2018 at 0:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.