【问题标题】:How do I convert an enum to a list in C#? [duplicate]如何在 C# 中将枚举转换为列表? [复制]
【发布时间】:2010-11-13 03:12:29
【问题描述】:

有没有办法将enum 转换为包含所有枚举选项的列表?

【问题讨论】:

标签: c# .net enums


【解决方案1】:

这将返回一个枚举的所有值的IEnumerable<SomeEnum>

Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();

如果您希望它成为List&lt;SomeEnum&gt;,只需在.Cast&lt;SomeEnum&gt;() 之后添加.ToList()

要在数组上使用 Cast 函数,您需要在 using 部分中包含 System.Linq

【讨论】:

  • 实际上 Cast() 的结果是一个 IEnumerable 所以如果你想要一个数组,你必须将你的行更改为:var array = Enum.GetValues(typeof(SomeEnum)).Cast&lt;SomeEnum&gt;().ToArray();
  • 那是多余的,意味着额外的复制。 Enum.GetValues 已经返回一个数组,所以你只需要做var values = (SomeEnum[])Enum.GetValues(typeof(SomeEnum))
  • 如果你只想要价值观然后再做演员:Enum.GetValues(typeof(SomeEnum)).Cast&lt;SomeEnum&gt;().Cast&lt;int&gt;().ToList()
  • 太棒了。刚刚意识到列表的顺序可以通过枚举的“值”来指定。例如: enum Foo { A = 1, B = 2, D = 4, C = 3, } => 一旦通过 GetValue 和 Cast 运行,那么顺序是 A、B、C、D。太棒了!跨度>
  • 如果它是 int 值的枚举... Enum.GetValues(typeof(EnumType)).Cast().ToArray();
【解决方案2】:

更简单的方法:

Enum.GetValues(typeof(SomeEnum))
    .Cast<SomeEnum>()
    .Select(v => v.ToString())
    .ToList();

【讨论】:

  • 为什么在 Cast 和 Select 之间使用 ToList()?这比公认的答案容易得多?它和它一样,只是你最后转换为string
  • 这个非常简单的操作只比较代码量。除此之外,这更像是解决此问题的 .NETy 解决方案。同意 ToList()。
  • 我认为你现在可以使用 Enum.GetNames(typeof(SomeEnum)).ToList()
  • @JasonWilczak 是的,请注意,如果枚举类型定义了“同义词”,则它们是不等价的,即相同基础值的多个命名常量。例如,Enum.GetNames(typeof(System.Net.HttpStatusCode)) 将获得 alldistinct 名称,而来自答案的方法将获得一些重复的字符串(因为 v.ToString() 将为每个重复的基础整数值)。见System.Net.HttpStatusCode enum documentation
  • 任何考虑这一点的人,请注意 ToString() 在枚举上的性能很糟糕,在内部它使用反射。它比字符串 -> 枚举查找表慢 1000 倍(毫不夸张)。
【解决方案3】:

简短的回答是,使用:

(SomeEnum[])Enum.GetValues(typeof(SomeEnum))

如果你需要一个局部变量,它是var allSomeEnumValues = (SomeEnum[])Enum.GetValues(typeof(SomeEnum));

为什么是这样的语法?!

static 方法 GetValues 是在旧的 .NET 1.0 时代引入的。它返回一个运行时类型为SomeEnum[] 的一维数组。但由于它是一种非泛型方法(直到 .NET 2.0 才引入泛型),它不能这样声明其返回类型(编译时返回类型)。

.NET 数组确实有一种协方差,但是因为SomeEnum 将是一个值类型,并且因为数组类型协方差不适用于值类型,他们甚至不能将返回类型声明为object[]Enum[]。 (这与例如 this overload of GetCustomAttributes from .NET 1.0 不同,它具有编译时返回类型 object[] 但实际上返回类型为 SomeAttribute[] 的数组,其中 SomeAttribute 必须是引用类型。)

因此,.NET 1.0 方法必须将其返回类型声明为System.Array。但我向你保证,它是SomeEnum[]

每次使用相同的枚举类型再次调用GetValues 时,它都必须分配一个新数组并将值复制到新数组中。那是因为数组可能被方法的“消费者”写入(修改),所以他们必须创建一个新数组以确保值不变。 .NET 1.0 没有好的只读集合。

如果您需要许多不同位置的所有值的列表,请考虑只调用一次 GetValues 并将结果缓存在只读包装器中,例如:

public static readonly ReadOnlyCollection<SomeEnum> AllSomeEnumValues
    = Array.AsReadOnly((SomeEnum[])Enum.GetValues(typeof(SomeEnum)));

那么你可以多次使用AllSomeEnumValues,同一个集合可以安全地重复使用。

为什么使用.Cast&lt;SomeEnum&gt;() 不好?

许多其他答案使用.Cast&lt;SomeEnum&gt;()。问题在于它使用了Array 类的非通用IEnumerable 实现。这应该涉及将每个值装箱到System.Object 框中,然后使用Cast&lt;&gt; 方法再次取消装箱所有这些值。幸运的是,.Cast&lt;&gt; 方法似乎在开始迭代集合之前检查了其IEnumerable 参数(this 参数)的运行时类型,所以它毕竟不是那么糟糕。原来.Cast&lt;&gt; 允许同一个数组实例通过。

如果您通过.ToArray().ToList() 关注它,如:

Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList() // DON'T do this

您还有另一个问题:当您调用GetValues 时创建了一个新集合(数组),然后使用.ToList() 调用创建了一个新集合(List&lt;&gt;)。所以这是整个集合的一个(额外)冗余分配来保存值。


更新:自 .NET 5.0(从 2020 年起),以上信息已过时;终于有了一个泛型方法(泛型从 2005 年开始在 .NET Framework 2.0 中引入),所以现在您应该简单地使用:

Enum.GetValues<SomeEnum>()

其返回参数是强类型的(如SomeEnum[])。

【讨论】:

  • 我最终在这里寻找一种从枚举中获取 List 的方法,而不是数组。如果您只想遍历枚举,这很好,但是 .Cast().ToList() 为您提供了一个 IEnumerable 集合,这在某些情况下很有价值。
  • @DaveD 表达式(SomeEnum[])Enum.GetValues(typeof(SomeEnum)) 也是IEnumerableIEnumerable&lt;SomeEnum&gt;,它也是IListIList&lt;SomeEnum&gt;。但是,如果您以后需要添加或删除条目,以便列表的长度发生变化,您可以复制到List&lt;SomeEnum&gt;,但这不是最常见的需要。
  • 我一直想知道为什么他们不只是添加一个Enum.GetValue&lt;T&gt;()
【解决方案4】:

这是我喜欢的方式,使用 LINQ:

public class EnumModel
{
    public int Value { get; set; }
    public string Name { get; set; }
}

public enum MyEnum
{
    Name1=1,
    Name2=2,
    Name3=3
}

public class Test
{
        List<EnumModel> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => new EnumModel() { Value = (int)c, Name = c.ToString() }).ToList();

        // A list of Names only, does away with the need of EnumModel 
        List<string> MyNames = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => c.ToString()).ToList();

        // A list of Values only, does away with the need of EnumModel 
        List<int> myValues = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).Select(c => (int)c).ToList();

        // A dictionnary of <string,int>
        Dictionary<string,int> myDic = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToDictionary(k => k.ToString(), v => (int)v);
}

希望对你有帮助

【讨论】:

  • ((IEnumerable&lt;EnumModel&gt;)Enum.GetValues 应该是((IEnumerable&lt;MyEnum&gt;)Enum.GetValues
  • 感谢@StevenAnderson,我修复了anwser。
  • 这是一个很好的例子!我喜欢你展示模型、枚举和用法的方式。在看到你的答案之前,我有点坚持要做什么。谢谢!
  • 我在这部分收到 ReSharper 警告:((IEnumerable)Enum.GetValues(typeof(MyEnum)) 说“可疑演员:解决方案中没有继承的类型来自 System.Array 和 System.Collections.Generic.IEnumerable' 为了解决这个问题,我将该行更改为 Enum.GetValues(typeof(MyEnum)).Cast()
  • @Rich,从 Jeppe Stig Nielsen 阅读 anwser,我认为为了避免警告最好转换为 MyEnum 数组(而不是 Enum 的 IEnumerable)而不是使用 .Cast( )。
【解决方案5】:
List <SomeEnum> theList = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();

【讨论】:

  • 这会分配两个集合来保存值并丢弃其中一个集合。请参阅我最近的回答。
【解决方案6】:

很简单的答案

这是我在我的一个应用程序中使用的属性

public List<string> OperationModes
{
    get
    {
       return Enum.GetNames(typeof(SomeENUM)).ToList();
    }
}

【讨论】:

  • 只返回枚举成员的名字:(我想获取枚举成员的值
【解决方案7】:

我一直习惯于像这样获取enum 值的列表:

Array list = Enum.GetValues(typeof (SomeEnum));

【讨论】:

  • 这会给你一个数组,而不是列表。
【解决方案8】:

这里是为了有用...一些用于将值转换为列表的代码,它将枚举转换为文本的可读形式

public class KeyValuePair
  {
    public string Key { get; set; }

    public string Name { get; set; }

    public int Value { get; set; }

    public static List<KeyValuePair> ListFrom<T>()
    {
      var array = (T[])(Enum.GetValues(typeof(T)).Cast<T>());
      return array
        .Select(a => new KeyValuePair
          {
            Key = a.ToString(),
            Name = a.ToString().SplitCapitalizedWords(),
            Value = Convert.ToInt32(a)
          })
          .OrderBy(kvp => kvp.Name)
         .ToList();
    }
  }

.. 以及配套的 System.String 扩展方法:

/// <summary>
/// Split a string on each occurrence of a capital (assumed to be a word)
/// e.g. MyBigToe returns "My Big Toe"
/// </summary>
public static string SplitCapitalizedWords(this string source)
{
  if (String.IsNullOrEmpty(source)) return String.Empty;
  var newText = new StringBuilder(source.Length * 2);
  newText.Append(source[0]);
  for (int i = 1; i < source.Length; i++)
  {
    if (char.IsUpper(source[i]))
      newText.Append(' ');
    newText.Append(source[i]);
  }
  return newText.ToString();
}

【讨论】:

  • 当您说(T[])(Enum.GetValues(typeof(T)).Cast&lt;T&gt;()) 时,仔细查看括号,我们看到您实际上将Cast&lt;T&gt; 的返回值转换为T[]。这很令人困惑(也许它甚至会起作用)。跳过Cast&lt;T&gt; 电话。有关详细信息,请参阅我的新答案。
【解决方案9】:
Language[] result = (Language[])Enum.GetValues(typeof(Language))

【讨论】:

    【解决方案10】:
    public class NameValue
    {
        public string Name { get; set; }
        public object Value { get; set; }
    }
    
    public class NameValue
    {
        public string Name { get; set; }
        public object Value { get; set; }
    }
    
    public static List<NameValue> EnumToList<T>()
    {
        var array = (T[])(Enum.GetValues(typeof(T)).Cast<T>()); 
        var array2 = Enum.GetNames(typeof(T)).ToArray<string>(); 
        List<NameValue> lst = null;
        for (int i = 0; i < array.Length; i++)
        {
            if (lst == null)
                lst = new List<NameValue>();
            string name = array2[i];
            T value = array[i];
            lst.Add(new NameValue { Name = name, Value = value });
        }
        return lst;
    }
    

    将枚举转换为列表更多可用信息here

    【讨论】:

    • T[] 的返回值转换为Cast&lt;T&gt; 会造成不必要的混乱。请参阅我最近的回答。
    【解决方案11】:
    private List<SimpleLogType> GetLogType()
    {
      List<SimpleLogType> logList = new List<SimpleLogType>();
      SimpleLogType internalLogType;
      foreach (var logtype in Enum.GetValues(typeof(Log)))
      {
        internalLogType = new SimpleLogType();
        internalLogType.Id = (int) (Log) Enum.Parse(typeof (Log), logtype.ToString(), true);
        internalLogType.Name = (Log)Enum.Parse(typeof(Log), logtype.ToString(), true);
        logList.Add(internalLogType);
      }
      return logList;
    }
    

    在顶部代码中,Log 是一个 Enum,SimpleLogType 是一个日志结构。

    public enum Log
    {
      None = 0,
      Info = 1,
      Warning = 8,
      Error = 3
    }
    

    【讨论】:

    • 您的foreach 变量具有编译时类型object(写为var),但它确实是Log 值(运行时类型)。无需拨打ToString,然后拨打Enum.Parse。用这个来开始你的foreachforeach (var logtype in (Log[])Enum.GetValues(typeof(Log))) { ... }
    【解决方案12】:
    /// <summary>
    /// Method return a read-only collection of the names of the constants in specified enum
    /// </summary>
    /// <returns></returns>
    public static ReadOnlyCollection<string> GetNames()
    {
        return Enum.GetNames(typeof(T)).Cast<string>().ToList().AsReadOnly();   
    }
    

    其中 T 是一种枚举类型; 添加这个:

    using System.Collections.ObjectModel; 
    

    【讨论】:

      【解决方案13】:

      如果您希望 Enum int 作为键和名称作为值,最好将数字存储到数据库并且它来自 Enum!

      void Main()
      {
           ICollection<EnumValueDto> list = EnumValueDto.ConvertEnumToList<SearchDataType>();
      
           foreach (var element in list)
           {
              Console.WriteLine(string.Format("Key: {0}; Value: {1}", element.Key, element.Value));
           }
      
           /* OUTPUT:
              Key: 1; Value: Boolean
              Key: 2; Value: DateTime
              Key: 3; Value: Numeric         
           */
      }
      
      public class EnumValueDto
      {
          public int Key { get; set; }
      
          public string Value { get; set; }
      
          public static ICollection<EnumValueDto> ConvertEnumToList<T>() where T : struct, IConvertible
          {
              if (!typeof(T).IsEnum)
              {
                  throw new Exception("Type given T must be an Enum");
              }
      
              var result = Enum.GetValues(typeof(T))
                               .Cast<T>()
                               .Select(x =>  new EnumValueDto { Key = Convert.ToInt32(x), 
                                             Value = x.ToString(new CultureInfo("en")) })
                               .ToList()
                               .AsReadOnly();
      
              return result;
          }
      }
      
      public enum SearchDataType
      {
          Boolean = 1,
          DateTime,
          Numeric
      }
      

      【讨论】:

        【解决方案14】:

        您可以使用以下通用方法:

        public static List<T> GetItemsList<T>(this int enums) where T : struct, IConvertible
        {
            if (!typeof (T).IsEnum)
            {
                throw new Exception("Type given must be an Enum");
            }
        
            return (from int item in Enum.GetValues(typeof (T))
                    where (enums & item) == item
                    select (T) Enum.Parse(typeof (T), item.ToString(new CultureInfo("en")))).ToList();
        }
        

        【讨论】:

        • 您首先获取值,然后将每个值转换为int,然后在int 上使用奇怪的文化调用ToString,然后将字符串解析回类型T?投反对票。
        • 是的,将所有值转换为 int 以进行检查,枚举是否包含项目,当转换为字符串以解析枚举时。这种方法对 BitMask 更有用。不需要 CultureInfo。
        • 你的参数和值不匹配
        猜你喜欢
        • 2013-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-21
        • 2013-08-03
        • 1970-01-01
        • 2012-07-12
        相关资源
        最近更新 更多