Как я могу привести int к enum?

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3 414
0
1 538 210
32
Перейти к ответу Данный вопрос помечен как решенный

Ответы 32

Ответ принят как подходящий

Из int:

YourEnum foo = (YourEnum)yourInt;

Из строки:

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.")
}

Обновлять:

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

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

Это должно быть правильно: YourEnum foo = (YourEnum) Enum.Parse (typeof (YourEnum), yourString) ИЛИ YourEnum foo = (YourEnum) Enum.Parse (typeof (YourEnum), yourInt) - в зависимости от обстоятельств.

Tathagat Verma 24.11.2011 11:24

@FlySwat, что, если YourEnum является динамическим и будет известен только во время выполнения, а я хочу преобразовать в Enum?

Shimmy Weitzhandler 19.02.2012 13:56

@ Шимми. Если перечисление известно только во время выполнения, сохраните его динамическим. Безопасность типов (строгая типизация) в любом случае может гарантировать только компилятор. Вы не можете строго вводить объект во время выполнения. Ближе всего к этому можно подойти с помощью универсальных типов, но универсальный тип должен быть известен во время компиляции. T ToEnum<T>(int x) { return (T)x; }, но реального преимущества перед прямым литьем нет.

Olivier Jacot-Descombes 21.02.2013 19:40

Быстрый вопрос, если бы вы вернулись с YourEnum foo на int anInt, введите: anInt = (int)foo;, это сработает?

Logan 13.04.2013 13:24

@Logan Конечно, работает. (Если базовый целочисленный тип перечисления не int, вместо этого приведенный к этому базовому целочисленному типу. Но крайне редко, что базовый тип должен быть чем-то другим, кроме просто int.)

Jeppe Stig Nielsen 15.04.2013 22:05

Имейте в виду, что Enum.Parse НЕ будет работать, если ваш код запутан. Во время выполнения после обфускации строка сравнивается с именами перечислений, и на этом этапе имена перечислений не такие, как вы ожидаете. В результате ваш синтаксический анализ не удастся там, где он преуспел раньше.

jropella 26.04.2013 22:03
ОСТЕРЕГАТЬСЯ If you use the "from a string" syntax above and pass in an invalid string that is a number (e.g. "2342342" -- assuming that's not a value of your enum), it will actually allow that without throwing an error! Your enum will have that value (2342342) even though it's not a valid choice in the enum itself.
JoeCool 25.06.2013 19:14

Я думаю, что этот ответ сейчас немного устарел. В настоящее время для строки вам действительно следует использовать var result = Enum.TryParse(yourString, out yourEnum) (и проверять результат, чтобы определить, не удалось ли преобразование).

Justin T Conroy 27.11.2013 01:40

@JustinTConroy Не знаю, согласен ли я с этим. В моих программах, если преобразование не удается, это часто неисправимая ошибка, поэтому я хочу, чтобы было создано исключение.

jackvsworld 01.02.2014 04:02

Функция Parse представляет собой классический пример неприятного исключения. То есть исключение, которое возникает в совершенно неисключительных обстоятельствах, обычно из-за неудачного дизайнерского решения. Разработчики C# признали этот неудачный дизайн и позже добавили TryParse для решения этой проблемы. TryParse возвращает логическое значение, которое указывает, был ли синтаксический анализ успешным или неудачным, поэтому вы должны использовать это логическое значение вместо обработчика исключений. См. Сообщение в блоге Эрика Липперта о досадных исключениях для получения дополнительной информации.

Justin T Conroy 03.02.2014 21:28

Также возможно сделать Enum.Parse нечувствительным к регистру, добавив к вызову значение параметра true: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);

Erik Schierboom 05.02.2014 16:18

Возможно ли, что преобразование из int работает, даже если значение int отсутствует в перечислении? Я просто попробовал это в .net 3.5, и, похоже, он работает, что довольно сбивает с толку.

Santhos 07.10.2014 14:31

Enum.ToObject - это то, что я искал. Это именно то, что вам нужно при динамической работе с перечислениями, и у вас есть тип, который, как вы знаете, является перечислением, но не можете доказать это компилятору, что не позволит вам выполнить приведение из значения int к произвольному типу.

Colin 08.12.2014 22:10

@Santhos Да, есть Enum.IsDefined(), чтобы проверить, существует ли значение, которое вы хотите преобразовать, в вашем перечислении.

Thaoden 06.03.2015 13:37

@JustinTConroy За исключением того, что это не так. Когда вы вызываете Parse, вы доверяете правильности входного значения, а когда это не так, это ошибка в коде (и там должно быть исключение). Если вы имеете дело с пользовательским вводом, вам всегда следует вызывать TryParse, поскольку недопустимый ввод не является исключением. В статье, которую вы связали, это упоминается в «99% случаев использования этого метода - преобразование строк, вводимых пользователем», это ошибка, метод не предназначен для обработки пользовательского ввода, TryParse.

Aidiakapi 17.08.2015 19:09

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

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

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

MyEnum e = (MyEnum)3;

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

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

Помните, что вы не можете использовать Enum.IsDefined, если вы используете атрибут Flags, а значение представляет собой комбинацию флагов, например: Keys.L | Ключи.Контроль

dtroy 31.07.2009 08:49

Что касается Enum.IsDefined, имейте в виду, что это может быть опасно: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx

adrian 04.12.2013 15:26

Я предпочитаю это определение: "Возвращает указание, существует ли константа с указанным значением в указанном перечислении" от MSDN

Pap 18.08.2014 23:13

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

Pap 18.08.2014 23:20

Обратите внимание, что значение Enum по умолчанию - int, но его можно изменить, что может сделать приведение опасным. Проверьте ответ @atlastes.

daniloquio 04.04.2018 16:57

@adrian, можешь ли ты дать краткий пример опасного сценария? С трудом оборачиваюсь вокруг этого документа.

Michael Crenshaw 01.11.2018 20:42

@ mac9416 Я попытался привести краткий пример на gist.github.com/alowdon/f7354cda97bac70b44e1c04bc0991bcc - в основном, используя IsDefined для проверки входных значений, вы оставляете себя уязвимым для людей, добавляющих новые значения перечисления позже, которые пройдут проверку IsDefined (поскольку новое значение существует в новом коде ), но который может не работать с исходным кодом, который вы написали. Поэтому безопаснее явно указывать значения перечисления, которые ваш код может обрабатывать.

adrian 13.11.2018 01:43

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

var MyEnumType = typeof(MyEnum);

Потом:

Enum.ToObject(typeof(MyEnum), 3)

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

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

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

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

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

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

orion elenzil 20.11.2015 03:50

На самом деле это не так уж и отличается от наиболее популярного ответа. В этом ответе также обсуждается использование Enum.IsDefined после преобразования строки в тип Enum. Таким образом, даже если строка была введена без ошибок, Enum.IsDefined все равно ее поймает.

Don Cheadle 20.12.2017 19:17

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

Это полезно при преобразовании из строки. Но не при преобразовании из int.

CodesInChaos 01.11.2011 19:08

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

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

Для обработки пользовательского ввода, вероятно, будет хорошей идеей вызвать перегрузку Enum.Parse, которая позволяет указать, что сравнение НЕ будет чувствительным к регистру (т.е. пользователь, вводящий «красный» (нижний регистр), приведет к сбою приведенного выше кода без этого изменения .)

BrainSlugs83 05.06.2013 00:56

Удобно, но вопрос конкретно про ints.

BJury 27.05.2015 13:18

это также работает, если строка является целым числом, например. «2»

TruthOf42 06.10.2016 22:19

Это вызовет исключение, если enumString имеет значение null (вчера была аналогичная проблема). Рассмотрите возможность использования TryParse вместо Parse. TryParse также проверит, является ли T типом Enum

Justin 18.10.2016 18:03

Этот тип метода расширения на System.String выглядит как загрязнение пространства имен.

Mr Anderson 13.05.2019 23:13

В последней версии C# /. NET вы можете использовать E вместо T, поэтому вы уверены, что метод вызывается в классе Enum.

Jimi 13.12.2019 11:29

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

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

Вы возвращаете значение по умолчанию (T), если оно не определено. Как это помогает идентифицировать неопределенные?

Ε Г И І И О 11.09.2020 06:01

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


 }
}

Чтобы преобразовать строку в ENUM или int в константу ENUM, нам нужно использовать функцию Enum.Parse. Вот видео на YouTube https://thewikihow.com/video_4nhx4VwdRDk, которое на самом деле демонстрирует строку со строкой, и то же самое применимо к int.

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

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

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

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

Перечисление в .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__ хранится отдельно от значений перечисления. В случае перечисления 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();
}

Я понимаю, что это старый пост, но как получить такой уровень знаний в C#? Это из-за прочтения спецификации C#?

Rolan 15.11.2015 03:19

@Rolan Иногда мне хочется, чтобы об этом спрашивало больше людей. :-) Честно говоря, не знаю; Я пытаюсь понять, как все работает, и получить информацию везде, где могу. Я прочитал стандарт C#, но я также регулярно декомпилирую код с помощью Reflector (я даже много смотрю на ассемблерный код x86) и провожу множество небольших экспериментов. Также в этом случае помогает знание других языков; Я занимаюсь CS около 30 лет, и в какой-то момент некоторые вещи стали «логичными» - например, перечисление должно быть целыми типами, потому что в противном случае взаимодействие будет нарушено (или ваша производительность упадет насмарку).

atlaste 15.11.2015 14:38

Я считаю, что ключом к правильной разработке программного обеспечения является знание того, как все работает. Для меня это означает, что если вы напишете кусок кода, вы знаете, как он примерно переводится на f.ex. операции процессора и выборки / записи в память. Если вы спросите, как достичь этого уровня, я бы посоветовал создать массу небольших тестовых примеров, усложняя их по ходу дела, каждый раз пытаясь предсказать результат, а потом тестировать их (включая декомпиляцию и т. д.). Разобравшись во всех деталях и характеристиках, вы можете проверить, правильно ли вы все поняли в (скучном) стандарте. По крайней мере, таков мой подход.

atlaste 15.11.2015 14:43

Фантастический ответ, спасибо! В вашем последнем примере кода он вызывает исключение во время выполнения, потому что o является объектом. Вы можете преобразовать переменную int в short, если она находится в пределах короткого диапазона.

gravidThoughts 11.08.2016 20:04

@gravidThoughts Спасибо. На самом деле это операция распаковки, поэтому она не будет выполнять никаких неявных преобразований, подобных тем, которые вы описываете. Приведение иногда сбивает с толку в C#, если вы не знаете подробностей ... В любом случае, поскольку int! = short, он выдаст (распаковка не удалась). Если вы сделаете object o = (short)5;, он будет работать, потому что тогда типы будут совпадать. Дело не в дальности, а в типе.

atlaste 12.08.2016 09:43

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

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

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

перечисления заменили использование таких целочисленных констант, поскольку они обеспечивают большую безопасность типов

Paul Richards 01.09.2014 11:41

Пол, это метод сбора связанных констант int (например, констант идентификатора базы данных), чтобы их можно было использовать напрямую, без необходимости приводить их к int каждый раз, когда они используются. Их тип целое число является, а не, например, DatabaseIdsEnum.

Ted 01.09.2014 13:37

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

Thierry 10.09.2014 21:33

Но перечисления также гарантируют, что все значения уникальны, чего в этом подходе также нет.

derHugo 11.10.2019 01:32

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

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

Вопрос конкретно касается целых чисел.

BJury 27.05.2015 13:13

Юй, пожалуйста, отредактируйте свой ответ, чтобы все знали, что Enum.TryParse будет работать со строкой значения или имени перечисления (я не мог устоять)

JeremyWeir 10.02.2016 08:37

Джереми, Вейр работает над этим (тоже не удержался).

huysentruitw 29.01.2018 15:20

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

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

Теперь это можно улучшить с помощью C# 7.3, ограничив Enum вместо struct, что означает, что нам не нужно полагаться на проверку во время выполнения!

Scott 09.11.2018 20:03

Я больше не знаю, где я беру часть этого расширения перечисления, но это из 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. Пожалуйста, добавьте значение Дефолт в первую очередь вашего перечисления. Что используется в 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;
    }
}

Примечание: Здесь я пытаюсь преобразовать значение в 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);

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

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

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 не является определенной записью в перечислении, вы можете использовать оператор else, чтобы установить enumString в значение по умолчанию. Спасибо

NDUF 27.01.2021 07:05

Простой и понятный способ преобразования int в enum в C#:

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

Вы просто используете Явное преобразование Cast int to enum или enum to 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
    }
}

Вот метод расширения, который преобразует 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);
    }

Для большей надежности вам следует предусмотреть релаксацию соответствия типов.

public static T ToEnum<T>(dynamic value)
{
    if (value == null)
    {
        // default value of an enum is the object that corresponds to
        // the default value of its underlying type
        // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table
        value = Activator.CreateInstance(Enum.GetUnderlyingType(typeof(T)));
    }
    else if (value is string name)
    {
        return (T)Enum.Parse(typeof(T), name);
    }

    return (T)Enum.ToObject(typeof(T),
             Convert.ChangeType(value, Enum.GetUnderlyingType(typeof(T))));
}

Прецедент

[Flags]
public enum A : uint
{
    None  = 0, 
    X     = 1 < 0,
    Y     = 1 < 1
}

static void Main(string[] args)
{
    var value = EnumHelper.ToEnum<A>(7m);
    var x = value.HasFlag(A.X); // true
    var y = value.HasFlag(A.Y); // true

    var value2 = EnumHelper.ToEnum<A>("X");

    var value3 = EnumHelper.ToEnum<A>(null);

    Console.ReadKey();
}

Это хороший ответ. Жаль, что на данный момент это так далеко на странице!

MikeBeaton 20.02.2020 19:34

Просто сделайте так, как показано ниже:

int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;

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

int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
    TargetEnum target = (TargetEnum)intToCast ;
}
else
{
   // Throw your exception.
}

Обратите внимание, что использование IsDefined является дорогостоящим и даже большим, чем просто приведение типов, поэтому решение использовать его или нет зависит от вашей реализации.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace SamplePrograme
{
    public class Program
    {
        public enum Suit : int
        {
            Spades = 0,
            Hearts = 1,
            Clubs = 2,
            Diamonds = 3
        }

        public static void Main(string[] args)
        {
            //from string
            Console.WriteLine((Suit) Enum.Parse(typeof(Suit), "Clubs"));

            //from int
            Console.WriteLine((Suit)1);

            //From number you can also
            Console.WriteLine((Suit)Enum.ToObject(typeof(Suit) ,1));
        }
    }
}

Вы можете использовать метод расширения.

public static class Extensions
{

    public static T ToEnum<T>(this string data) where T : struct
    {
        if (!Enum.TryParse(data, true, out T enumVariable))
        {
            if (Enum.IsDefined(typeof(T), enumVariable))
            {
                return enumVariable;
            }
        }

        return default;
    }

    public static T ToEnum<T>(this int data) where T : struct
    {
        return (T)Enum.ToObject(typeof(T), data);
    }
}

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

Enum:

public enum DaysOfWeeks
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7,
}

Использование:

 string Monday = "Mon";
 int Wednesday = 3;
 var Mon = Monday.ToEnum<DaysOfWeeks>();
 var Wed = Wednesday.ToEnum<DaysOfWeeks>();

Просто вы можете преобразовать int в enum

 public enum DaysOfWeeks
    {
        Monday = 1,
        Tuesday = 2,
        Wednesday = 3,
        Thursday = 4,
        Friday = 5,
        Saturday = 6,
        Sunday = 7,
    } 

    var day= (DaysOfWeeks)5;
    Console.WriteLine("Day is : {0}", day);
    Console.ReadLine();

Если бы приведение работало, вы не смогли бы сохранить его как int.

a p 19.06.2020 04:28

Пожалуйста, попробуйте понять int до Enum, я думаю, что это ответ, который вам поможет.

Inam Abbas 23.06.2020 13:58

Мне нужны две инструкции:

YourEnum possibleEnum = (YourEnum)value; // There isn't any guarantee that it is part of the enum
if (Enum.IsDefined(typeof(YourEnum), possibleEnum))
{
    // Value exists in YourEnum
}

var result = Enum.TryParse(yourString, out yourEnum) 

И обязательно проверьте результат, чтобы определить, не удалось ли выполнить преобразование.

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

var enumValue = (MyEnum?)enumInt;

if (!enumValue.HasValue)
{
    throw new ArgumentException(nameof(enumValue));
}

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