Литой int в enum в с#

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

21 ответов


из строки:

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;

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

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-это структура, которая сопоставляет набор значений (полей) базовому типу (по умолчанию int). Однако вы можете выбрать интегральный тип, который соответствует вашему перечислению:

public enum Foo : short

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

если вы посмотрите на это с точки зрения IL, перечисление (normal, 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__ хранится отдельно от значения enum. В случае перечисления 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();
}

рассмотрим пример:

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

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

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

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


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

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

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


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

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

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

for (var flagIterator = 0x1; flagIterator <= 0x80000000; flagIterator <<= 1)
{
    // Check to see if the current flag exists in the bit mask
    if ((intValue & flagIterator) != 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), flagIterator))
            ListOfEnumValues.Add((MyEnum)flagIterator);
    }
}

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

var MyEnumType = typeof(MyEnumType);

затем:

Enum.ToObject(typeof(MyEnum), 3)

это перечисление флагов, знающее безопасный метод преобразования:

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: struct
{
  var enumType = typeof (T);
  if (!enumType.IsEnum)
  {
    throw new ArgumentException("The generic type must be an enum.");
  }
  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.Функция разбора. Вот видео на youtubehttps://www.youtube.com/watch?v=4nhx4VwdRDk которые фактически демонстрируют со строкой, и то же самое относится к int.

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

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

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


из строки: (перечисление.Синтаксический анализ устарел, используйте перечисление.Метод 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. Мне также нужно было дружеское имя, а не просто перечисление.Метод 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;
    }
}

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

    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;

Это может помочь вам конвертировать любые входные данные для пользователя желаемого перечисление. Предположим, у вас есть перечисление, подобное ниже, которое по умолчанию int. Пожалуйста, добавьте по умолчанию значение сначала вашего перечисления. Который используется в helpers 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 Если вы определяете enum как это, который байт тип.

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

вам нужно изменить синтаксический анализ при вспомогательном методе из

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

to

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

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