Приведите int к перечислению в C #

2749

Как int можно передать в enum в С#?

Теги:
casting
enums

23 ответа

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

Из строки:

YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// the foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
  throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")

Из int:

YourEnum foo = (YourEnum)yourInt;

Update:

Из числа вы также можете

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
  • 0
    Это должно быть правильно: YourEnum foo = (YourEnum) Enum.Parse (typeof (YourEnum), yourString) ИЛИ YourEnum foo = (YourEnum) Enum.Parse (typeof (YourEnum), yourInt) - в зависимости от обстоятельств.
  • 22
    @FlySwat, что если YourEnum является динамическим и будет известен только во время выполнения, а я хочу преобразовать его в Enum ?
Показать ещё 17 комментариев
728

Просто бросьте его:

MyEnum e = (MyEnum)3;

Вы можете проверить, находится ли он в диапазоне, используя Enum.IsDefined:

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
  • 202
    Остерегайтесь, вы не можете использовать Enum.IsDefined, если используете атрибут Flags, а значение представляет собой комбинацию флагов, например: Keys.L | Keys.Control
  • 13
    Что касается Enum.IsDefined , Enum.IsDefined , что это может быть опасно: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
Показать ещё 7 комментариев
211

В качестве альтернативы используйте метод расширения вместо однострочного:

public static T ToEnum<T>(this string enumString)
{
    return (T) Enum.Parse(typeof (T), enumString);
}

Применение:

Color colorEnum = "Red".ToEnum<Color>();

ИЛИ

string color = "Red";
var colorEnum = color.ToEnum<Color>();
  • 7
    Для обработки пользовательского ввода, вероятно, хорошей идеей будет вызвать перегрузку Enum.Parse, которая позволяет вам указать, что сравнение НЕ чувствительно к регистру (т. Е. Пользователь, набрав «red» (нижний регистр), вылетит из приведенного выше кода без этого изменения). .)
  • 33
    Круто, разве что это не вопрос.
Показать ещё 3 комментария
126

Я думаю, чтобы получить полный ответ, люди должны знать, как enums работают внутри .NET.

Как работает материал

Перечисление в .NET - это структура, которая отображает набор значений (полей) в базовый тип (по умолчанию это int). Тем не менее, вы можете выбрать тип интеграла, который соответствует вашему перечислению:

public enum Foo : short

В этом случае перечисление преобразуется в тип данных short, что означает, что он будет храниться в памяти как короткий и будет вести себя как короткий, когда вы используете и используете его.

Если вы посмотрите на него с точки зрения IL, (enum, int) enum выглядит следующим образом:

.class public auto ansi serializable sealed BarFlag extends System.Enum
{
    .custom instance void System.FlagsAttribute::.ctor()
    .custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }

    .field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
    .field public static literal valuetype BarFlag Foo1 = int32(1)
    .field public static literal valuetype BarFlag Foo2 = int32(0x2000)

    // and so on for all flags or enum values

    .field public specialname rtspecialname int32 value__
}

Что следует обратить ваше внимание на то, что value__ хранится отдельно от значений перечисления. В случае перечисления Foo выше тип value__ - int16. Это в основном означает, что вы можете хранить все, что хотите, в перечислении, , если типы соответствуют.

В этот момент я хотел бы указать, что System.Enum - это тип значения, что в основном означает, что BarFlag будет занимать 4 байта в памяти, а Foo займет 2 - например. размер базового типа (это на самом деле более сложный, чем тот, но эй...).

Ответ

Итак, если у вас есть целое число, которое вы хотите сопоставить с перечислением, время выполнения должно делать только 2 вещи: скопируйте 4 байта и назовите это что-то еще (имя перечисления). Копирование является неявным, поскольку данные хранятся как тип значения - это в основном означает, что если вы используете неуправляемый код, вы можете просто обменять перечисления и целые числа без копирования данных.

Чтобы сделать это безопасным, я считаю, что наилучшей практикой известно, что базовые типы являются одинаковыми или неявно конвертируемыми и для обеспечения наличия значений перечисления (они не отмечены по умолчанию!).

Чтобы узнать, как это работает, попробуйте следующий код:

public enum MyEnum : int
{
    Foo = 1,
    Bar = 2,
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)5;
    var e2 = (MyEnum)6;

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

Обратите внимание, что также работает отбрасывание на e2! Из перспективы компилятора выше это имеет смысл: поле value__ просто заполняется либо 5, либо 6, а когда Console.WriteLine вызывает ToString(), имя e1 разрешается, а имя e2 - нет.

Если это не то, что вы намеревались, используйте Enum.IsDefined(typeof(MyEnum), 6), чтобы проверить, действительно ли значение, которое вы создаете, сопоставляет определенному перечислению.

Также обратите внимание, что я явно о базовом типе перечисления, хотя компилятор действительно проверяет это. Я делаю это, чтобы я не сталкивался с неожиданностями в будущем. Чтобы увидеть эти сюрпризы в действии, вы можете использовать следующий код (на самом деле я видел, как это произошло в коде базы данных):

public enum MyEnum : short
{
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)32769; // will not compile, out of bounds for a short

    object o = 5;
    var e2 = (MyEnum)o;     // will throw at runtime, because o is of type int

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}
  • 7
    Я понимаю, что это старый пост, но как вы получаете этот уровень знаний в C #? Это из чтения спецификации C #?
  • 17
    @Rolan Иногда я хочу, чтобы больше людей спрашивали об этом. :-) Если честно, я действительно не знаю; Я пытаюсь понять, как все работает, и получать информацию везде, где только могу. Я читал стандарт C #, но я также регулярно декомпилирую код с помощью Reflector (я даже много смотрю на код ассемблера x86) и провожу множество маленьких экспериментов. Кроме того, знание других языков помогает в этом случае; Я занимаюсь CS уже около 30 лет, и в какой-то момент некоторые вещи становятся «логичными» - например. Перечисление должно быть целочисленным, потому что в противном случае взаимодействие прервется (или ваша производительность снизится).
Показать ещё 5 комментариев
102

Возьмем следующий пример:

int one = 1;
MyEnum e = (MyEnum)one;
58

Я использую этот кусок кода для преобразования int в свой список перечислений:

if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }

Я считаю это лучшим решением.

  • 1
    Не работает с перечислениями флагов
  • 1
    это хорошо. Я был удивлен, что нет исключения при преобразовании недопустимого значения в перечисление с внутренней поддержкой.
Показать ещё 1 комментарий
49

Ниже приведен хороший класс утилиты для Enums

public static class EnumHelper
{
    public static int[] ToIntArray<T>(T[] value)
    {
        int[] result = new int[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = Convert.ToInt32(value[i]);
        return result;
    }

    public static T[] FromIntArray<T>(int[] value) 
    {
        T[] result = new T[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = (T)Enum.ToObject(typeof(T),value[i]);
        return result;
    }


    internal static T Parse<T>(string value, T defaultValue)
    {
        if (Enum.IsDefined(typeof(T), value))
            return (T) Enum.Parse(typeof (T), value);

        int num;
        if(int.TryParse(value,out num))
        {
            if (Enum.IsDefined(typeof(T), num))
                return (T)Enum.ToObject(typeof(T), num);
        }

        return defaultValue;
    }
}
38

Для числовых значений это безопаснее, так как он вернет объект независимо от того, что:

public static class EnumEx
{
    static public bool TryConvert<T>(int value, out T result)
    {
        result = default(T);
        bool success = Enum.IsDefined(typeof(T), value);
        if (success)
        {
            result = (T)Enum.ToObject(typeof(T), value);
        }
        return success;
    }
}
  • 0
    Это не работает с перечислениями флагов
38

Если вы готовы к созданию 4.0 .NET, здесь есть новая функция Enum.TryParse(), которая очень полезна и хорошо работает с [Flags] атрибут. См. Метод Enum.TryParse(String, TEnum%)

  • 19
    Это полезно при конвертации из строки. Но не при конвертации из int.
27

Если у вас есть целое число, которое действует как битовая маска и может представлять одно или несколько значений в перечислении [Flags], вы можете использовать этот код для анализа значений отдельных флагов в списке:

for (var flagIterator = 0; flagIterator < 32; flagIterator++)
{
    // Determine the bit value (1,2,4,...,Int32.MinValue)
    int bitValue = 1 << flagIterator;

    // Check to see if the current flag exists in the bit mask
    if ((intValue & bitValue) != 0)
    {
        // If the current flag exists in the enumeration, then we can add that value to the list
        // if the enumeration has that flag defined
        if (Enum.IsDefined(typeof(MyEnum), bitValue))
            Console.WriteLine((MyEnum)bitValue);
    }
}

Обратите внимание, что это предполагает, что базовый тип enum является 32-разрядным целым числом со знаком. Если бы это был другой числовой тип, вам пришлось бы изменить жестко запрограммированный 32, чтобы отразить биты этого типа (или получить его программным путем, используя Enum.GetUnderlyingType()).

  • 0
    Этот цикл никогда не заканчивается? flagIterator = 0x00000001, flagIterator = 0x00000002, flagIterator = 0x00000004, ..., flagIterator = 0x40000000, flagIterator = 0x80000000, flagIterator = 0x00000000. Другими словами, значение всегда будет ниже, чем 0x80000000, потому что оно переполняется до нуля после случая, когда бит D31 = 1. Затем оно остается 0 навсегда, потому что при сдвиге влево значение 0 дает 0
  • 0
    Отличный улов @ christiangingras, спасибо! Я изменил ответ, чтобы учесть это, и он должен учитывать, когда установлен старший бит (то есть 0x80000000 / Int32.MinValue)
25

Иногда у вас есть объект типа MyEnum. Как

var MyEnumType = typeof(MyEnumType);

Тогда:

Enum.ToObject(typeof(MyEnum), 3)
21

Это безопасный метод преобразования с учетом перечисления флагов:

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: Enum
{
  var enumType = typeof (T);
  var success = Enum.IsDefined(enumType, instance);
  if (success)
  {
    result = (T)Enum.ToObject(enumType, instance);
  }
  else
  {
    result = default(T);
  }
  return success;
}
  • 1
    Теперь это можно улучшить с помощью C # 7.3, ограничившись Enum вместо struct , что означает, что нам не нужно полагаться на проверку во время выполнения!
19

Изображение 939

Чтобы преобразовать строку в ENUM или int в константу ENUM, нам нужно использовать функцию Enum.Parse. Вот видео youtube https://www.youtube.com/watch?v=4nhx4VwdRDk, которые на самом деле демонстрируются со строкой, и то же самое относится к int.

Код идет, как показано ниже, где "красный" - это строка, а "MyColors" - это цвет ENUM, который имеет цветовые константы.

MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
16

Слегка уйти от исходного вопроса, но я нашел ответ на вопрос Qaru Получить значение int из перечисления. Создайте статический класс с помощью свойств public const int, позволяя вам легко собрать кучу связанных констант int, а затем не использовать их при int при их использовании.

public static class Question
{
    public static readonly int Role = 2;
    public static readonly int ProjectFunding = 3;
    public static readonly int TotalEmployee = 4;
    public static readonly int NumberOfServers = 5;
    public static readonly int TopBusinessConcern = 6;
}

Очевидно, что некоторые функции типа перечисления будут потеряны, но для хранения связки констант идентификатора базы данных это выглядит как довольно аккуратное решение.

  • 5
    перечисления заменили использование таких целочисленных констант, так как они обеспечивают большую безопасность типов
  • 1
    Пол, это метод сбора связанных между собой констант типа int (например, константы идентификатора базы данных), чтобы их можно было использовать напрямую, не приводя их к int каждый раз, когда они используются. Их тип - целое число, а не, например, DatabaseIdsEnum.
Показать ещё 1 комментарий
12

Из строки: (Enum.Parse устарел, используйте Enum.TryParse)

enum Importance
{}

Importance importance;

if (Enum.TryParse(value, out importance))
{
}
  • 3
    Вопрос конкретно задается о целых числах.
  • 3
    Ю, пожалуйста, отредактируйте свой ответ, чтобы все знали, что Enum.TryParse будет работать со строкой значения или имени перечисления (я не смог устоять)
Показать ещё 1 комментарий
12

Это разделяет целые числа или строки на целевое перечисление с частичным совпадением в dot.NET 4.0 с использованием дженериков, таких как класс утилиты Tawani выше. Я использую его для преобразования переменных ключа командной строки, которые могут быть неполными. Поскольку перечисление не может быть нулевым, вы должны логически предоставить значение по умолчанию. Его можно назвать так:

var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);

Здесь код:

using System;

public class EnumParser<T> where T : struct
{
    public static T Parse(int toParse, T defaultVal)
    {
        return Parse(toParse + "", defaultVal);
    }
    public static T Parse(string toParse, T defaultVal) 
    {
        T enumVal = defaultVal;
        if (defaultVal is Enum && !String.IsNullOrEmpty(toParse))
        {
            int index;
            if (int.TryParse(toParse, out index))
            {
                Enum.TryParse(index + "", out enumVal);
            }
            else
            {
                if (!Enum.TryParse<T>(toParse + "", true, out enumVal))
                {
                    MatchPartialName(toParse, ref enumVal);
                }
            }
        }
        return enumVal;
    }

    public static void MatchPartialName(string toParse, ref T enumVal)
    {
        foreach (string member in enumVal.GetType().GetEnumNames())
        {
            if (member.ToLower().Contains(toParse.ToLower()))
            {
                if (Enum.TryParse<T>(member + "", out enumVal))
                {
                    break;
                }
            }
        }
    }
}

FYI: Вопрос о целых числах, о которых никто не упоминал, также будет явно преобразован в Enum.TryParse()

9

Ниже приведен немного лучший метод расширения

public static string ToEnumString<TEnum>(this int enumValue)
        {
            var enumString = enumValue.ToString();
            if (Enum.IsDefined(typeof(TEnum), enumValue))
            {
                enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
            }
            return enumString;
        }
9

В моем случае мне нужно было вернуть перечисление из службы WCF. Мне также понадобилось дружественное имя, а не только enum.ToString().

Здесь мой класс WCF.

[DataContract]
public class EnumMember
{
    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public int Value { get; set; }

    public static List<EnumMember> ConvertToList<T>()
    {
        Type type = typeof(T);

        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be of type enumeration.");
        }

        var members = new List<EnumMember>();

        foreach (string item in System.Enum.GetNames(type))
        {
            var enumType = System.Enum.Parse(type, item);

            members.Add(
                new EnumMember() { Description = enumType.GetDescriptionValue(), Value = ((IConvertible)enumType).ToInt32(null) });
        }

        return members;
    }
}

Здесь используется метод расширения, который получает описание из Enum.

    public static string GetDescriptionValue<T>(this T source)
    {
        FieldInfo fileInfo = source.GetType().GetField(source.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fileInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);            

        if (attributes != null && attributes.Length > 0)
        {
            return attributes[0].Description;
        }
        else
        {
            return source.ToString();
        }
    }

Реализация:

return EnumMember.ConvertToList<YourType>();
7

Я больше не знаю, где я получаю часть этого расширения enum, но это из stackoverflow. Прошу прощения за это! Но я взял это и изменил его для перечислений с помощью флагов. Для перечислений с флажками я сделал это:

  public static class Enum<T> where T : struct
  {
     private static readonly IEnumerable<T> All = Enum.GetValues(typeof (T)).Cast<T>();
     private static readonly Dictionary<int, T> Values = All.ToDictionary(k => Convert.ToInt32(k));

     public static T? CastOrNull(int value)
     {
        T foundValue;
        if (Values.TryGetValue(value, out foundValue))
        {
           return foundValue;
        }

        // For enums with Flags-Attribut.
        try
        {
           bool isFlag = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
           if (isFlag)
           {
              int existingIntValue = 0;

              foreach (T t in Enum.GetValues(typeof(T)))
              {
                 if ((value & Convert.ToInt32(t)) > 0)
                 {
                    existingIntValue |= Convert.ToInt32(t);
                 }
              }
              if (existingIntValue == 0)
              {
                 return null;
              }

              return (T)(Enum.Parse(typeof(T), existingIntValue.ToString(), true));
           }
        }
        catch (Exception)
        {
           return null;
        }
        return null;
     }
  }

Пример:

[Flags]
public enum PetType
{
  None = 0, Dog = 1, Cat = 2, Fish = 4, Bird = 8, Reptile = 16, Other = 32
};

integer values 
1=Dog;
13= Dog | Fish | Bird;
96= Other;
128= Null;
7

Различные способы передачи в и из Enum

enum orientation : byte
{
 north = 1,
 south = 2,
 east = 3,
 west = 4
}

class Program
{
  static void Main(string[] args)
  {
    orientation myDirection = orientation.north;
    Console.WriteLine("myDirection = {0}", myDirection); //output myDirection =north
    Console.WriteLine((byte)myDirection); //output 1

    string strDir = Convert.ToString(myDirection);
        Console.WriteLine(strDir); //output north

    string myString = "north"; //to convert string to Enum
    myDirection = (orientation)Enum.Parse(typeof(orientation),myString);


 }
}
6

Он может помочь вам преобразовать любые входные данные в желаемый перечисление пользователя. Предположим, что у вас есть перечисление вроде ниже, по умолчанию int. Добавьте сначала Default значение по умолчанию. Используется в помощниках medthod, когда нет совпадения с входным значением.

public enum FriendType  
{
    Default,
    Audio,
    Video,
    Image
}

public static class EnumHelper<T>
{
    public static T ConvertToEnum(dynamic value)
    {
        var result = default(T);
        var tempType = 0;

        //see Note below
        if (value != null &&
            int.TryParse(value.ToString(), out  tempType) && 
            Enum.IsDefined(typeof(T), tempType))
        {
            result = (T)Enum.ToObject(typeof(T), tempType); 
        }
        return result;
    }
}

N.B: Здесь я пытаюсь проанализировать значение в int, потому что enum по умолчанию int Если вы определяете перечисление, подобное типу byte.

public enum MediaType : byte
{
    Default,
    Audio,
    Video,
    Image
} 

Вам нужно изменить разбор по вспомогательному методу из

int.TryParse(value.ToString(), out  tempType)

к

byte.TryParse(value.ToString(), out tempType)

Я проверяю свой метод на следующие входы

EnumHelper<FriendType>.ConvertToEnum(null);
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("-1");
EnumHelper<FriendType>.ConvertToEnum("6");
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("2");
EnumHelper<FriendType>.ConvertToEnum(-1);
EnumHelper<FriendType>.ConvertToEnum(0);
EnumHelper<FriendType>.ConvertToEnum(1);
EnumHelper<FriendType>.ConvertToEnum(9);

извините за мой английский

3

простой и понятный способ приведения int к enum в С#:

 public class Program
    {
        public enum Color : int
        {
            Blue = 0,
            Black = 1,
            Green = 2,
            Gray = 3,
            Yellow =4
        }

        public static void Main(string[] args)
        {
            //from string
            Console.WriteLine((Color) Enum.Parse(typeof(Color), "Green"));

            //from int
            Console.WriteLine((Color)2);

            //From number you can also
            Console.WriteLine((Color)Enum.ToObject(typeof(Color) ,2));
        }
    }
0

Вы просто используете явное преобразование Cast int в enum или enum в int

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((int)Number.three); //Output=3

            Console.WriteLine((Number)3);// Outout three
            Console.Read();
        }

        public enum Number 
        {
            Zero = 0,
            One = 1,
            Two = 2,
            three = 3           
        }
    }

Ещё вопросы

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