C # Lặp lại thông qua một enum? (Lập chỉ mục một System.Array)


113

Tôi có mã sau:

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

Tuy nhiên, tôi không thể lập chỉ mục các giá trị. Có cách nào dễ dàng hơn để làm điều này không?

Hoặc tôi đã bỏ lỡ một cái gì đó hoàn toàn!

Câu trả lờ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));
}

Hoặc, bạn có thể ép kiểu System.Array được trả về:

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

Tuy nhiên, bạn có thể chắc chắn rằng GetValues ​​trả về các giá trị theo thứ tự giống như GetNames trả về tên không?


3
"Nhưng, bạn có thể chắc chắn rằng GetValues ​​trả về các giá trị theo thứ tự giống như GetNames trả về tên không?" - Đây là một điểm rất tốt và là điều mà tôi chưa giải quyết được! Tôi nghĩ rằng giải pháp đầu tiên của bạn có thể sẽ cung cấp một cách để khớp các giá trị và chuỗi một cách đáng tin cậy
TK.

Xin chào, tôi đã thấy đề cập trước đây về nghi ngờ "chỉ mục không khớp" xảy ra khi thực hiện việc này; tuy nhiên, tôi vẫn chưa khám phá ra liệu điều này có thực sự là một mối quan tâm hay không? Có bất kỳ trường hợp cuối cùng nào mà theo đó giả định này có thể trở nên tồi tệ không? Cám ơn!
Funka,

Bạn có thể muốn chuyển "val" thứ hai thành một int, nếu bạn muốn khắc phục sự cố không khớp giá trị vì Enum.GetName(typeof(MyEnum), val), (int)val)trong đó đầu ra cung cấp tên và số kiểu liệt kê.
Greg

GetValues ​​và GetNames trả về theo cùng một thứ tự, cụ thể là: "Các phần tử của mảng giá trị trả về được sắp xếp theo giá trị nhị phân của các hằng số được liệt kê (nghĩa là theo độ lớn không dấu của chúng)."
Russell Borogove

Tôi tin rằng bạn cũng có thể sử dụng LINQ trực tiếp bằng cách gọi Cast<T>vào kết quả:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull

33

Bạn cần ép kiểu mảng - mảng được trả về thực sự thuộc kiểu được yêu cầu, tức là myEnum[]nếu bạn yêu cầu typeof(myEnum):

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

Sau đó, values[0]vv


9

Bạn có thể truyền Mảng đó sang các loại Mảng khác nhau:

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

hoặc nếu bạn muốn các giá trị nguyên:

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

Tất nhiên, bạn có thể lặp lại các mảng được đúc đó :)


7

Làm thế nào về một danh sách từ điển?

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

và tất nhiên bạn có thể thay đổi kiểu giá trị từ điển thành bất kỳ giá trị enum của bạn.


Tôi nghĩ rằng đây sẽ là cách để đi, nhưng không thoải mái vì enum nằm trong một vùng mã mà tôi không kiểm soát được!
TK.

1
Giải pháp duy nhất tôi đã tìm thấy nhận được các giá trị enum số nguyên thực tế!
SharpC

5

Một giải pháp khác, với những khả năng thú vị:

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

Đây là một cái khác. Chúng tôi cần cung cấp những cái tên thân thiện cho EnumValues ​​của mình. Chúng tôi đã sử dụng System.ComponentModel.DescriptionAttribute để hiển thị một giá trị chuỗi tùy chỉnh cho mỗi giá trị 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;
    }
}

Đang sử dụng

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



    static void Main(string[] args)
    {

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

Điều này sẽ kết thúc trả về "Cái gì đó 1", "Cái gì đó 2"


1
Chỉ tốt nếu các mô tả là tĩnh ... nếu các mô tả của bạn cần thay đổi dựa trên cơ sở phiên bản thì cách tiếp cận này sẽ không hoạt động.
Llyle

3

Điều gì về việc sử dụng một vòng lặp foreach, có thể bạn có thể làm việc với nó?

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

một cái gì đó như vậy có lẽ?


Tôi đã nghĩ vậy ... nhưng tôi cần có quyền truy cập vào cả tên và giá trị trong 'đồng bộ hóa' ... nói rằng tên [2] được ghép nối với các giá trị [2] và tôi không chắc về cách đạt được điều này trong một vòng lặp foreach!
TK.

Tôi đã thêm một ví dụ - hãy xem điều đó có hữu ích không.
TWith2Sugars

3

Câu hỏi cũ nhưng cách tiếp cận gọn gàng hơn một chút bằng cách sử dụng LINQ's .Cast<>()

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

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

2

Mảng có một phương thức GetValue (Int32) mà bạn có thể sử dụng để truy xuất giá trị tại một chỉ mục được chỉ định.

Array.GetValue


2

Bạn có thể đơn giản hóa việc này bằng cách sử dụng chuỗi định dạng. Tôi sử dụng đoạn mã sau trong thông báo sử dụng:

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

Bộ định dạng D định dạng giá trị enum dưới dạng số thập phân. Ngoài ra còn có một chỉ số X cung cấp đầu ra thập lục phân.

Bộ xác định G định dạng một enum dưới dạng một chuỗi. Nếu thuộc tính Flags được áp dụng cho enum thì các giá trị kết hợp cũng được hỗ trợ. Có một thông số F hoạt động như thể Cờ luôn hiện diện.

Xem Enum.Format ().


2

Trong kết quả Enum.GetValues, ép kiểu sang int tạo ra giá trị số. Sử dụng ToString () tạo ra tên thân thiện. Không cần các lệnh gọi khác tới 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

Đây là một cách đơn giản để lặp qua đối tượng Enum tùy chỉnh của bạn

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

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

Next

1
Tôi nghĩ OP đã yêu cầu C #.
jm.

0

Câu hỏi cổ xưa, nhưng câu trả lời của 3Dave cung cấp cách tiếp cận dễ dàng nhất. Tôi cần một phương thức trợ giúp nhỏ để tạo tập lệnh Sql để giải mã một giá trị enum trong cơ sở dữ liệu để gỡ lỗi. Nó hoạt động tuyệt vời:

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

Tôi có nó trong một phương thức tĩnh, vì vậy cách sử dụng là:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.