Вопрос

Как может int быть отброшенным к enum на С#?

Это было полезно?

Решение

Из строки:

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;

Обновлять:

С номера вы также можете

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);

Другие советы

Просто произнесите это:

MyEnum e = (MyEnum)3;

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

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }

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

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

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

Как это работает

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

public enum Foo : short

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

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

.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 - например.размер базового типа (на самом деле это сложнее, но эй...).

Ответ

Итак, если у вас есть целое число, которое вы хотите сопоставить с перечислением, среда выполнения должна сделать только две вещи:скопируйте 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();
}

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

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

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

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

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

Ниже приведен хороший служебный класс для 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;
    }
}

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

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

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

Если у вас есть целое число, которое действует как битовая маска и может представлять одно или несколько значений в перечислении [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())

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

var MyEnumType = typeof(MyEnumType);

Затем:

Enum.ToObject(typeof(MyEnum), 3)

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

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

enter image description here

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

Код выглядит так, как показано ниже, где «красный» — это строка, а «MyColors» — это ENUM цвета, который имеет цветовые константы.

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

Немного отошел от первоначального вопроса, но нашел ответ на вопрос о переполнении стека Получить значение 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;
}

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

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

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

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

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

enum Importance
{}

Importance importance;

if (Enum.TryParse(value, out importance))
{
}

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

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

В моем случае мне нужно было вернуть перечисление из службы 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;
    }
}

Вот метод Extension, который получает описание из 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>();

Различные способы кастинга к и от 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);


 }
}

Я больше не знаю, откуда я взял часть этого расширения перечисления, но это из 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;

Это может помочь вам преобразовать любые входные данные в желаемые пользователем значения. перечисление.Предположим, у вас есть перечисление, подобное приведенному ниже, которое по умолчанию интервал.Пожалуйста, добавьте По умолчанию значение в начале вашего перечисления.Который используется в вспомогательном методе, когда не найдено совпадения с входным значением.

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

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

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

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

Вот метод расширения, который приводит Int32 к Enum.

Он учитывает побитовые флаги, даже если их значение превышает максимально возможное.Например, если у вас есть перечисление с возможностями 1, 2, и 4, но int 9, он понимает, что как 1 в отсутствие 8.Это позволяет обновлять данные раньше обновлений кода.

   public static TEnum ToEnum<TEnum>(this int val) where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
        {
            return default(TEnum);
        }

        if (Enum.IsDefined(typeof(TEnum), val))
        {//if a straightforward single value, return that
            return (TEnum)Enum.ToObject(typeof(TEnum), val);
        }

        var candidates = Enum
            .GetValues(typeof(TEnum))
            .Cast<int>()
            .ToList();

        var isBitwise = candidates
            .Select((n, i) => {
                if (i < 2) return n == 0 || n == 1;
                return n / 2 == candidates[i - 1];
            })
            .All(y => y);

        var maxPossible = candidates.Sum();

        if (
            Enum.TryParse(val.ToString(), out TEnum asEnum)
            && (val <= maxPossible || !isBitwise)
        ){//if it can be parsed as a bitwise enum with multiple flags,
          //or is not bitwise, return the result of TryParse
            return asEnum;
        }

        //If the value is higher than all possible combinations,
        //remove the high imaginary values not accounted for in the enum
        var excess = Enumerable
            .Range(0, 32)
            .Select(n => (int)Math.Pow(2, n))
            .Where(n => n <= val && n > 0 && !candidates.Contains(n))
            .Sum();

        return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);
    }

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

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

Вы просто используете Явное преобразование Приведение int к перечислению или перечисление к 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           
        }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top