C # Iterasi melalui enum? (Mengindeks System.Array)

113

Saya memiliki kode berikut:

// 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] ); 
}

Namun, saya tidak dapat mengindeks nilai. Adakah cara yang lebih mudah untuk melakukan ini?

Atau apakah saya melewatkan sesuatu sama sekali!

TK.
sumber

Jawaban:

204
Array values = Enum.GetValues(typeof(myEnum));

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

Atau, Anda dapat mentransmisikan System.Array yang dikembalikan:

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]);
}

Tapi, dapatkah Anda yakin bahwa GetValues ​​mengembalikan nilai dalam urutan yang sama seperti GetNames mengembalikan nama?

Frederik Gheysels
sumber
3
"Tapi, dapatkah Anda yakin bahwa GetValues ​​mengembalikan nilai dalam urutan yang sama seperti GetNames mengembalikan nama?" - Ini adalah poin yang sangat bagus dan sesuatu yang belum saya bahas! Saya pikir solusi pertama Anda mungkin akan memberikan cara untuk mencocokkan nilai dan string dengan andal
TK.
Halo, saya pernah melihat penyebutan sebelumnya tentang kecurigaan "index-mismatching" yang terjadi saat melakukan ini; Namun, saya belum menemukan apakah ini benar-benar menjadi perhatian atau tidak? Adakah kasus definitif di mana asumsi ini bisa salah? Terima kasih!
Funka
Anda mungkin ingin mentransmisikan "val" kedua ke int, jika Anda ingin memecahkan masalah ketidakcocokan nilai seperti Enum.GetName(typeof(MyEnum), val), (int)val)di mana keluaran menyediakan nama dan nomor pencacahan.
Greg
GetValues ​​dan GetNames kembali dalam urutan yang sama, yaitu: "Elemen dari larik nilai yang dikembalikan diurutkan berdasarkan nilai biner dari konstanta yang disebutkan (yaitu, dengan besarnya unsigned)."
Russell Borogove
Saya yakin Anda juga dapat menggunakan LINQ secara langsung dengan Cast<T>melihat hasilnya:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull
33

Anda perlu mentransmisikan array - array yang dikembalikan sebenarnya dari tipe yang diminta, yaitu myEnum[]jika Anda meminta typeof(myEnum):

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

Lalu values[0]dll

Marc Gravell
sumber
9

Anda dapat mentransmisikan Array itu ke berbagai jenis Array:

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

atau jika Anda menginginkan nilai integer:

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

Anda tentu saja dapat mengulang larik yang dicor tersebut :)

Arcturus
sumber
7

Bagaimana dengan daftar kamus?

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));
}

dan tentu saja Anda dapat mengubah tipe nilai kamus menjadi apa pun nilai enum Anda.

mrtaikandi
sumber
Saya pikir ini akan menjadi cara yang harus dilakukan, tetapi sayangnya enum berada di area kode yang tidak dapat saya kendalikan!
TK.
1
Satu-satunya solusi yang saya temukan yang mendapatkan nilai enum integer aktual!
SharpC
5

Solusi lain, dengan kemungkinan menarik:

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;
  } 
}
Paul
sumber
4

Ini satu lagi. Kami memiliki kebutuhan untuk memberikan nama yang bersahabat untuk EnumValues ​​kami. Kami menggunakan System.ComponentModel.DescriptionAttribute untuk menampilkan nilai string kustom untuk setiap nilai enum.

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;
    }
}

Digunakan

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



    static void Main(string[] args)
    {

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

Ini akan berakhir dengan mengembalikan "Sesuatu 1", "Sesuatu 2"

Kevin Castle
sumber
1
Hanya bagus jika deskripsinya statis ... jika deskripsi Anda perlu diubah berdasarkan instance, maka pendekatan ini tidak akan berfungsi.
Llyle
3

Bagaimana dengan menggunakan foreach loop, mungkin Anda bisa menggunakannya?

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

sesuatu seperti itu mungkin?

TWith2Sugars
sumber
Saya telah mempelajari itu ... tetapi saya perlu mendapatkan akses ke nama dan nilai di 'sync' ... katakanlah nama [2] dipasangkan dengan nilai [2] dan saya tidak yakin bagaimana cara mencapainya di loop foreach!
TK.
Saya telah menambahkan contoh - lihat apakah itu membantu.
TWith2Sugars
3

Pertanyaan lama, tetapi pendekatan yang sedikit lebih bersih menggunakan LINQ .Cast<>()

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

foreach(var val in values)
{
    Console.WriteLine("Member: {0}",val.ToString());     
}
Simpan
sumber
2

Array memiliki metode GetValue (Int32) yang dapat Anda gunakan untuk mengambil nilai pada indeks yang ditentukan.

Array.GetValue

Plastik gelembung
sumber
2

Anda dapat menyederhanakan ini menggunakan string format. Saya menggunakan potongan berikut dalam pesan penggunaan:

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);
}

Penentu format D memformat nilai enum sebagai desimal. Ada juga penentu X yang memberikan keluaran heksadesimal.

Penentu G memformat enum sebagai string. Jika atribut Flags diterapkan ke enum maka nilai gabungan juga didukung. Ada penentu F yang bertindak seolah-olah Bendera selalu ada.

Lihat Enum.Format ().

Frank Szczerba
sumber
2

Dalam hasil Enum.GetValues, mentransmisikan ke int menghasilkan nilai numerik. Menggunakan ToString () menghasilkan nama yang akrab. Tidak diperlukan panggilan lain ke Enum.GetName.

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
 */
Mike Wodarczyk
sumber
0

Berikut adalah cara sederhana untuk mengulang melalui objek Enum kustom Anda

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

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

Next
Chev
sumber
1
Saya pikir OP meminta C #.
jm.
0

Pertanyaan kuno, tetapi jawaban 3Dave memberikan pendekatan termudah. Saya membutuhkan sedikit metode pembantu untuk menghasilkan skrip Sql untuk memecahkan kode nilai enum dalam database untuk debugging. Ini bekerja dengan baik:

    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,";
    }

Saya memilikinya dalam metode statis, jadi penggunaannya adalah:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Wade Hatler
sumber