Вопрос: Вставить int для перечисления в C #


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


2516


источник


Ответы:


Из строки:

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

3063



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

MyEnum e = (MyEnum)3;

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

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

706



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

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

192



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

115



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

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

88



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

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

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


53



Below is a nice utility class for 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;
    }
}

44



If you're ready for the 4.0 .NET Framework, there's a new Enum.TryParse() function that's very useful and plays well with the [Flags] attribute. See Enum.TryParse Method (String, TEnum%)


37