C # วนซ้ำผ่าน enum? (การสร้างดัชนี System.Array)


113

ฉันมีรหัสต่อไปนี้:

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

อย่างไรก็ตามฉันไม่สามารถจัดทำดัชนีค่าได้ มีวิธีที่ง่ายกว่านี้ไหม

หรือว่าฉันพลาดอะไรไปอย่างสิ้นเชิง!

คำตอบ:


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

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

หรือคุณสามารถใช้ System.Array ที่ส่งคืน:

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

แต่คุณแน่ใจได้หรือไม่ว่า GetValues ​​ส่งคืนค่าในลำดับเดียวกับที่ GetNames ส่งกลับชื่อ


3
"แต่คุณแน่ใจได้หรือไม่ว่า GetValues ​​ส่งคืนค่าในลำดับเดียวกับที่ GetNames ส่งกลับชื่อ" - นี่เป็นจุดที่ดีมากและฉันยังไม่ได้พูดถึง! ฉันคิดว่าโซลูชันแรกของคุณน่าจะเป็นวิธีจับคู่ค่าและสตริงได้อย่างน่าเชื่อถือ
TK

สวัสดีฉันเคยเห็นการกล่าวถึงก่อนหน้านี้ว่าเกิดข้อสงสัยเกี่ยวกับ "ดัชนีไม่ตรงกัน" เมื่อทำสิ่งนี้ อย่างไรก็ตามฉันยังไม่พบว่าสิ่งนี้น่ากังวลจริงหรือไม่? มีกรณีที่สรุปได้หรือไม่ที่สมมติฐานนี้อาจผิดพลาด? ขอบคุณ!
Funka

คุณอาจต้องการร่าย "val" ตัวที่สองเป็น int หากคุณต้องการแก้ไขปัญหาค่าไม่ตรงกันเนื่องจากEnum.GetName(typeof(MyEnum), val), (int)val)เอาต์พุตระบุชื่อและหมายเลขการแจงนับ
Greg

GetValues ​​และ GetNames ส่งคืนในลำดับเดียวกันกล่าวคือ: "องค์ประกอบของอาร์เรย์ค่าที่ส่งคืนจะถูกจัดเรียงตามค่าไบนารีของค่าคงที่ที่แจกแจง (นั่นคือตามขนาดที่ไม่ได้ลงนาม)"
Russell Borogove

ฉันเชื่อว่าคุณสามารถใช้ LINQ ได้โดยตรงโดยเรียกCast<T>ผลลัพธ์:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull

33

คุณต้องแคสต์อาร์เรย์ - อาร์เรย์ที่ส่งคืนเป็นประเภทที่ร้องขอนั่นคือmyEnum[]ถ้าคุณขอtypeof(myEnum):

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

แล้วvalues[0]ฯลฯ


9

คุณสามารถส่ง Array นั้นไปยัง Arrays ประเภทต่างๆ:

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

หรือถ้าคุณต้องการค่าจำนวนเต็ม:

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

คุณสามารถทำซ้ำอาร์เรย์ที่หล่อเหล่านั้นได้แน่นอน :)


7

แล้วรายการพจนานุกรมล่ะ?

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

และแน่นอนคุณสามารถเปลี่ยนประเภทค่าพจนานุกรมเป็นค่า enum ของคุณได้


ฉันคิดว่านี่จะเป็นหนทางไป แต่น่าเสียดายที่ enum อยู่ในพื้นที่ของรหัสที่ฉันไม่สามารถควบคุมได้!
ทีเค.

1
ทางออกเดียวที่ฉันพบว่าได้รับค่า enum จำนวนเต็มจริง!
SharpC

5

อีกวิธีหนึ่งที่มีความเป็นไปได้ที่น่าสนใจ:

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

4

นี่คืออีกหนึ่ง เราจำเป็นต้องระบุชื่อที่จำง่ายสำหรับ EnumValues ​​ของเรา เราใช้ System.ComponentModel.DescriptionAttribute เพื่อแสดงค่าสตริงที่กำหนดเองสำหรับแต่ละค่า 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;
    }
}

ในการใช้งาน

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



    static void Main(string[] args)
    {

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

การดำเนินการนี้จะสิ้นสุดการส่งคืน "Something 1", "Something 2"


1
จะดีก็ต่อเมื่อคำอธิบายเป็นแบบคงที่ ... หากคำอธิบายของคุณจำเป็นต้องเปลี่ยนแปลงตามพื้นฐานของอินสแตนซ์วิธีนี้จะไม่ได้ผล
Llyle

3

แล้วการใช้ foreach loop ล่ะบางทีคุณอาจจะใช้มันได้?

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

อะไรแบบนั้นบางที?


ฉันมีสิ่งนั้น ... แต่ฉันต้องการเข้าถึงทั้งชื่อและค่าใน 'การซิงค์' ... บอกว่าชื่อ [2] จับคู่กับค่า [2] และฉันไม่แน่ใจว่าจะบรรลุเป้าหมายนี้ได้อย่างไรใน ห่วงหน้า!
ทีเค.

ฉันได้เพิ่มตัวอย่าง - ดูว่าช่วยได้ไหม
TWith2Sugars

3

คำถามเก่า แต่วิธีการที่สะอาดกว่าเล็กน้อยโดยใช้ LINQ .Cast<>()

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

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


2

คุณสามารถทำให้สิ่งนี้ง่ายขึ้นโดยใช้สตริงรูปแบบ ฉันใช้ตัวอย่างต่อไปนี้ในข้อความการใช้งาน:

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

ตัวระบุรูปแบบ D จัดรูปแบบค่า enum เป็นทศนิยม นอกจากนี้ยังมีตัวระบุ X ที่ให้เอาต์พุตเลขฐานสิบหก

ตัวระบุ G จัดรูปแบบ enum เป็นสตริง หากใช้แอตทริบิวต์ Flags กับ enum ค่าที่รวมจะได้รับการสนับสนุนเช่นกัน มีตัวระบุ F ที่ทำหน้าที่ราวกับว่ามีธงอยู่เสมอ

ดู Enum.Format ()


2

ในผลลัพธ์ Enum.GetValues ​​การแคสต์เป็น int จะสร้างค่าตัวเลข การใช้ ToString () สร้างชื่อที่จำง่าย ไม่จำเป็นต้องมีการเรียกอื่น ๆ ไปยัง 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
 */

0

นี่คือวิธีง่ายๆในการวนซ้ำผ่านอ็อบเจ็กต์ Enum ที่คุณกำหนดเอง

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

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

Next

1
ฉันคิดว่า OP ขอ C #
jm.

0

คำถามโบราณ แต่คำตอบของ 3Dave เป็นแนวทางที่ง่ายที่สุด ฉันต้องการวิธีการช่วยเหลือเล็กน้อยในการสร้างสคริปต์ Sql เพื่อถอดรหัสค่า enum ในฐานข้อมูลสำหรับการดีบัก มันใช้งานได้ดี:

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

ฉันมีมันในวิธีการคงที่ดังนั้นการใช้งานคือ:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.