Питання Вибрали int до переліку в C #


Як може int бути кинутим до enum в C #?


2571
2017-08-27 03:58


походження


Навпаки: get-int-value-from-enum - nawfal
Безкоштовно 5 хв відео, що охоплює найкращі відповіді нижче: app.deviq.com/courses/how-do-i-convert-int-to-enum-in-c-sharp - ssmith


Відповіді:


З рядка:

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

3122
2017-08-27 03:59



@FlySwat, що якщо YourEnum є динамічним і буде відомо лише під час виконання, і я хочу, щоб це перетворити на Enum? - Shimmy
Майте на увазі, що Enum.Parse НЕ буде працювати, якщо ваш код буде заплутаним. Під час запуску після обфускації рядок порівнюється з іменами переліку, і на даний момент імена енумов не такі, що ви очікуєте від них. Ваш синтаксичний аналіз не вдасться, коли вони досягли успіху в результаті. - jropella
БУДЬ-ЛАСКА Якщо ви використовуєте синтаксис "з рядка" вище та передаєте недійсний рядок, який є цифрою (наприклад, "2342342" - припущення, що це не значення вашого переліку), воно фактично дозволить це без викидання помилки! Ваш перерахунок буде мати таку цінність (2342342), навіть якщо це не є правильним вибором в enum. - JoeCool
Я думаю, що ця відповідь трохи застаріла зараз. Для рядка, ви повинні дійсно використовувати var result = Enum.TryParse(yourString, out yourEnum) в даний час (і перевірити результат, щоб визначити, якщо конверсія не вдалася). - Justin T Conroy
Це також можливо Enum.Parse бути нечутливим до регістру, додавши true значення параметра для дзвінка: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true); - Erik Schierboom


Просто киньте його:

MyEnum e = (MyEnum)3;

Ви можете перевірити, чи це використовується в діапазоні Enum.IsDefined:

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

721
2017-08-27 04:01



Остерігайтеся, що ви не можете використовувати Enum.IsDefined, якщо ви використовуєте атрибут Flags, а значення - комбінація прапорів, наприклад: Keys.L | Keys.Control - dtroy
Що стосується Enum.IsDefined, пам'ятайте, що це може бути небезпечно: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx - adrian
З іншого боку, якщо я перевіряю вхід на основі переліку, яку надає бібліотека, перш ніж відправити його в саму бібліотеку ... - Alexander
Я віддаю перевагу цьому визначення: "Повертає вказівку, чи існує константа з вказаним значенням у вказаному переліку" від MSDN - Pap
... Тому що ваше визначення може бути оманливим, оскільки ви говорите: "... перевірити, чи знаходиться він у діапазоні ..." що випливає з діапазону чисел із початковими та кінцевими межами ... - Pap


Крім того, скористайтеся методом розширення, а не однорядником:

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

198
2017-11-11 13:27



Для обробки вхідних даних користувача це, можливо, хороша ідея викликати перевантаження Enum.Parse, що дозволяє вказати, що порівняння НЕ буде чутливим до регістру (тобто користувач, що набрав "червоний" (нижній регістр), призведе до збою вищезазначеного коду без цієї зміни .) - BrainSlugs83
Прохолодно, хіба що це не питання. - nawfal
Handy, але питання конкретно про ints. - BJury
це також працює, якщо рядок є цілим числом, наприклад "2" - TruthOf42
Це викличе виняток, якщо enumString є нульовим (вчорашній аналогічний випадок). Подумайте про використання TryParse замість Parse. TryParse також перевірить, чи T є Enum Type - Justin


Я думаю, щоб отримати повну відповідь, люди повинні знати, як enums працюють всередині .NET.

Як все працює

Enum в .NET - це структура, яка наносить набір значень (полів) у базовий тип (за умовчанням є int) Тим не менш, ви можете вибрати інтегральний тип, який відображає ваш перелік:

public enum Foo : short

У цьому випадку перерахування перераховується на short тип даних, що означає, що він буде зберігатися в пам'яті як короткий і буде вести себе як короткий при відтворенні та використанні.

Якщо ви подивитеся на це з точки зору ІЛ, (звичайний, 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 - наприклад розмір основного типу (це насправді складніше, ніж це, але ей ...).

Відповідь

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

116
2018-04-03 07:39



Я розумію, що це старий пост, але як ви отримуєте цей рівень знань в c #? Це читати через специфікацію C #? - Rolan
@ Ролан Я іноді хочу, щоб більше людей запитали про це. :-) Чесно кажучи, я дійсно не знаю; Я намагаюся зрозуміти, як речі працюють і отримувати інформацію, де б я не змогла її отримати. Я прочитав стандарт C #, але я також регулярно декомпілюю код з Reflector (я навіть дивлюся на код x86 асемблер багато) і зробити безліч маленьких експериментів. Також, знаючи про інші мови допомагає у цьому випадку; Я займаюся КС протягом приблизно 30 років, і в якийсь момент деякі речі стають "логічними" - f.ex. перерахування має бути інтегральними типами, тому що інакше взаємодія буде перервана (або ваша продуктивність потрапляє до стоку). - atlaste
Я вважаю, що ключ до правильної розробки програмного забезпечення - це знання того, як це працює. Для мене це означає, що, якщо ви пишете шматок коду, ви знаєте, як це приблизно перекладається на f.ex. процесорні операції та пам'ять вибирає / пише. Якщо ви запитаєте, як дійти до цього рівня, я б запропонував побудувати тонну маленьких тестових випадків, щоб зробити їх жорсткішими, коли ви йдете, спробуйте спрогнозувати результат кожного разу та перевіряти їх пізніше (включаючи декомпіляцію тощо). Визначивши всі деталі та всі характеристики, ви можете перевірити, чи правильно ви знайшли його в (нульовий) стандарт. Принаймні, це буде моїм підходом. - atlaste
Фантастичний відповідь, дякую! У вашому останньому зразку коду він викидає виняток під час виконання, оскільки o є об'єктом. Ви можете передати значення змінної int до короткого, якщо він знаходиться в межах короткого діапазону. - gravidThoughts
@gravidThoughts Спасибо. Насправді це операція розпакування, тому вона не буде робити жодних неявних конверсій, як описані вами. Кастинг іноді заплутує в C #, якщо ви не знаєте подробиць ... Так чи інакше, тому що int ! = short, це буде кидати (розблокування не вдається). Якщо ти зробиш object o = (short)5;, він буде працювати, тому що типи будуть відповідати. Це не про діапазон, це дійсно про тип. - atlaste


Візьміть такий приклад:

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

89
2017-08-27 04:00





Я використовую цей шматок коду, щоб передати int до мого enum:

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

Я вважаю це найкращим рішенням.


54
2017-10-21 10:05



Не працює з прапорами enums - Daniel Fisher lennybacon
це добре. Я був здивований тим, що не виняток, коли відкидає недійсне значення до переліку int-backed. - orion elenzil
Це насправді не настільки відрізняється від найвищої оцінки. У цьому відповіді також обговорюється використання Enum.IsDefined після того, як ви видалите рядок у тип Enum. Таким чином, навіть якщо ланцюжок було випущено без помилок, Enum.IsDefined все одно потрапить на це - mmcrae


Нижче наведено хороший клас корисності для 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
2017-09-07 04:42





Якщо ви готові до версії 4.0 .NET Framework, є новий Enum.TryParse () функція, яка дуже корисна і добре відтворює атрибут [Flags]. Побачити Метод Enum.TryParse (String, TEnum%)


37
2017-11-01 14:58



Це корисно при перетворенні з ланцюжка. Але не при перетворенні з int. - CodesInChaos


Для числових значень це безпечніше, оскільки він поверне об'єкт незалежно від того, що:

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

37
2018-02-21 15:22



Це не працює з прапорцями - Daniel Fisher lennybacon


Якщо у вас є ціле число, яке діє як бітове маска і може представляти одне або декілька значень у переліку [Флаги], ви можете використовувати цей код для аналізу окремих значень прапорця у список:

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

25
2018-04-13 20:13





Іноді ви маєте об'єкт до MyEnum тип Люблю

var MyEnumType = typeof(MyEnumType);

Потім:

Enum.ToObject(typeof(MyEnum), 3)

22
2017-07-02 14:41