получить - перечисления c#




Вставить int для перечисления в C# (14)

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


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

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

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

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

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

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


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

enum Importance
{}

Importance importance;

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

Из строки:

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

Немного уйти от исходного вопроса, но я нашел ответ на вопрос о переполнении стека. Получите значение int из перечисления полезным. Создайте статический класс с public const 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;
}

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


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

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

Он может помочь вам преобразовать любые входные данные в желаемое имя пользователя. Предположим, что у вас есть перечисление вроде ниже, которое по умолчанию int . Добавьте сначала значение по умолчанию из вашего перечисления. Используется в помощниках 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;
    }
}

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

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

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


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

MyEnum e = (MyEnum)3;

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

if (Enum.IsDefined(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;
}

Это разделяет целые числа или строки на целевое перечисление с частичным совпадением в 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 ()


Я думаю, чтобы получить полный ответ, люди должны знать, как 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) чтобы проверить, действительно ли значение, которое вы 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 в мое перечисление:

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

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





casting