Как мне преобразовать перечисление в список в C #? [Дубликат]

449

Есть ли способ конвертировать enum в список, содержащий все параметры перечисления?

Показать ещё 1 комментарий
Теги:
enums

14 ответов

697
Лучший ответ

Это вернет IEnumerable<SomeEnum> всех значений Enum.

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

Если вы хотите, чтобы это было List<SomeEnum>, просто добавьте .ToList() после .Cast<SomeEnum>().

Чтобы использовать функцию Cast на Array, вам нужно иметь System.Linq в вашем разделе использования.

  • 0
    хорошо .. это работает Array arr = (Array) Enum.GetValues (typeof (SomeEnum)). Cast <SomeEnum> (); Правильно ли работать с этой строкой кода?
  • 3
    На самом деле результатом Cast <T> () является IEnumerable <T>, поэтому если вы хотите получить массив, вам нужно изменить строку на: var array = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToArray();
Показать ещё 6 комментариев
71

Гораздо проще:

Enum.GetValues(typeof(SomeEnum))
    .Cast<SomeEnum>()
    .Select(v => v.ToString())
    .ToList();
  • 13
    Почему ToList() между Cast и Select? И как это намного проще, чем принятый ответ? Это идентично этому, за исключением того, что вы конвертируете в string в конце.
  • 1
    Просто сравните количество кода для этой очень простой операции. Кроме того, это более. NETy решение этой проблемы. Согласитесь на ToList ().
Показать ещё 3 комментария
60

Короткий ответ:

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

Если вам нужна эта локальная переменная, она var allSomeEnumValues = (SomeEnum[])Enum.GetValues(typeof(SomeEnum));.

Почему синтаксис такой?!

Метод static GetValues был введен еще в старые .NET 1.0 дни. Он возвращает одномерный массив типа времени выполнения SomeEnum[]. Но поскольку это не общий метод (generics не был введен до .NET 2.0), он не может объявить его возвращаемый тип (тип возвращаемого времени компиляции) как таковой.

.NET-массивы имеют своего рода ковариацию, но поскольку SomeEnum будет значением типа, и поскольку ковариация типа массива не работает со значениями типов, они не могут даже объявить возвращаемый тип как object[] или Enum[]. (Это отличается от этой перегрузки GetCustomAttributes от .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<SomeEnum>()?

Многие другие ответы используют .Cast<SomeEnum>(). Проблема заключается в том, что он использует не-generic IEnumerable реализацию класса Array. Это должно было включать боксирование каждого из значений в поле System.Object, а затем с помощью метода Cast<> снова удалить все эти значения. К счастью, метод .Cast<>, по-видимому, проверяет тип времени выполнения своего параметра IEnumerable (параметр this), прежде чем он начнет выполнять итерацию через коллекцию, поэтому это не так уж плохо. Оказывается, .Cast<> пропускает один и тот же экземпляр массива.

Если вы следуете за ним .ToArray() или .ToList(), как в:

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

у вас возникла другая проблема: при вызове GetValues вы создаете новую коллекцию (массив), а затем создаете новую коллекцию (List<>) с вызовом .ToList(). Так что одно (дополнительное) избыточное выделение всей коллекции для хранения значений.

  • 1
    В итоге я искал способ получить список <> из моего перечисления, а не массив. Если вы хотите только пройтись по своему перечислению, это замечательно, но .Cast <type> (). ToList () предоставляет вам коллекцию IEnumerable, которая полезна в некоторых ситуациях.
  • 2
    @DaveD Выражение (SomeEnum[])Enum.GetValues(typeof(SomeEnum)) также имеет IEnumerable и IEnumerable<SomeEnum> , а также IList и IList<SomeEnum> . Но если вам нужно добавить или удалить записи позже, чтобы длина списка изменилась, вы можете скопировать в List<SomeEnum> , но это не самая обычная необходимость.
Показать ещё 1 комментарий
19
List <SomeEnum> theList = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();
  • 1
    Это выделяет две коллекции для хранения значений и отбрасывает одну из этих коллекций. Смотрите мой недавний ответ.
18

Вот как я люблю, используя 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();
}

Надеюсь, что это поможет

  • 11
    ((IEnumerable<EnumModel>)Enum.GetValues должен быть ((IEnumerable<MyEnum>)Enum.GetValues
  • 0
    Спасибо @StevenAnderson, я исправил ответ.
Показать ещё 3 комментария
8

очень простой ответ

Вот свойство, которое я использую в одном из моих приложений

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

Я всегда использовал список значений enum, подобных этому:

Array list = Enum.GetValues(typeof (SomeEnum));
  • 2
    Это даст вам массив, а не список <>.
4

Здесь для полезности... некоторый код для получения значений в списке, который преобразует перечисление в читаемую форму для текста

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();
}
  • 0
    Когда вы говорите (T[])(Enum.GetValues(typeof(T)).Cast<T>()) , внимательно изучая скобки, мы видим, что вы фактически приводите возвращаемое значение Cast<T> к T[] . Это довольно запутанно (и, возможно, удивительно, что это даже сработает). Пропустите вызов Cast<T> . Смотрите мой новый ответ для деталей.
3
Language[] result = (Language[])Enum.GetValues(typeof(Language))
2
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;
}

Преобразование Enum В список более доступной информации здесь.

  • 0
    Приведение к T[] возвращаемого значения Cast<T> неоправданно запутано. Смотрите мой недавний ответ.
1
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;
}

в верхнем коде, журнал - это перечисление, а SimpleLogType - это структура для журналов.

public enum Log
{
  None = 0,
  Info = 1,
  Warning = 8,
  Error = 3
}
  • 0
    Ваша переменная foreach имеет object типа времени компиляции (записанный как var ), но на самом деле это значение Log (тип времени выполнения). Нет необходимости вызывать ToString а затем Enum.Parse . Вместо этого начните свой foreach с этого: foreach (var logtype in (Log[])Enum.GetValues(typeof(Log))) { ... }
1
/// <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; 
0

Если вы хотите, чтобы 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
}
0

Вы можете использовать следующий общий метод:

    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();
    }
  • 0
    Сначала вы получаете значения, затем приводите каждое к int , затем вызываете ToString со странной культурой для этого int , а затем анализируете строку обратно к типу T ? Downvoted.
  • 0
    Да, приведение всех значений к int для проверки, содержит ли перечисление элемент, когда приведение к строке для анализа перечисления обратно. Этот метод более полезен с BitMask. КультураИнфо не требуется.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню