Avatar ·

Как преобразовать int в enum в C#? Приведение типов и Enum.Parse

Всем привет! Я начинающий C# разработчик и столкнулся с непонятной для меня ситуацией. У меня есть перечисление (enum) для статусов заказа: ```csharp public enum OrderStatus { Created = 1, Processing = 2, Shipped = 3, Delivered = 4 } ``` Из базы данных я получаю числовое значение статуса в виде int (например, 2). Мне нужно преобразовать этот int в элемент перечисления OrderStatus. Я пробовал просто присвоить: ```csharp int statusValue = 2; OrderStatus status = statusValue; // Ошибка компиляции! ``` Но получаю ошибку: "Cannot implicitly convert type 'int' to 'OrderStatus'". Я понимаю, что C# — строго типизированный язык, но как тогда правильно выполнить такое преобразование? Я слышал про явное приведение (cast) и про метод Enum.Parse, но не совсем понимаю, в чём разница и какой способ лучше использовать. Также меня интересует, что будет, если я передам число, которое не соответствует ни одному из значений enum (например, 5 или 0)? Будет ли исключение? И как безопасно обрабатывать такие случаи? Подскажите, пожалуйста, наиболее правильный и надёжный способ преобразования int в enum в C# с примерами кода. Заранее спасибо! <<>>

Основные способы преобразования int в enum

В C# есть два основных подхода: явное приведение типа (cast) и использование Enum.Parse / Enum.TryParse. Выбор зависит от контекста: известно ли вам, что значение гарантированно существует в перечислении, или нужна проверка.

1. Явное приведение (cast) — простой и быстрый способ

Самый производительный метод — использовать явное приведение типа. Он подходит, когда вы уверены, что целое число соответствует одному из значений enum:

int statusValue = 2;
OrderStatus status = (OrderStatus)statusValue; // status == OrderStatus.Processing

Console.WriteLine(status); // Выведет: Processing

Важно: C# позволяет привести любое целое число к любому enum, даже если такого значения нет. Это не вызовет исключения — просто получится "некорректное" значение enum.

int invalidValue = 99;
OrderStatus badStatus = (OrderStatus)invalidValue; // Ошибки НЕТ!
Console.WriteLine(badStatus); // Выведет: 99 (число, а не имя)

Чтобы проверить, существует ли значение в enum, используйте метод Enum.IsDefined():

int value = 5;
if (Enum.IsDefined(typeof(OrderStatus), value))
{
    OrderStatus status = (OrderStatus)value;
    Console.WriteLine($"Статус: {status}");
}
else
{
    Console.WriteLine($"Значение {value} не определено в перечислении");
}

2. Enum.Parse — для работы со строками

Если у вас строка (например, "2" или "Processing"), используйте Enum.Parse. Но для int он менее удобен, так как требует преобразования в строку:

string strValue = "2";
OrderStatus status = (OrderStatus)Enum.Parse(typeof(OrderStatus), strValue);

Обратите внимание: Enum.Parse выбросит ArgumentException, если строка не соответствует ни числу, ни имени элемента. Поэтому безопаснее использовать Enum.TryParse:

string input = "5";
if (Enum.TryParse<OrderStatus>(input, out OrderStatus result))
{
    Console.WriteLine($"Успешно: {result}");
}
else
{
    Console.WriteLine("Не удалось распарсить");
}

Но для преобразования из int в enum TryParse тоже работает, так как он принимает строковое представление числа:

int number = 3;
if (Enum.TryParse<OrderStatus>(number.ToString(), out OrderStatus status))
{
    Console.WriteLine(status); // Shipped
}

3. Рекомендации по выбору

  • Используйте явное приведение (cast), если вы на 100% уверены в корректности числа (например, значение получено из валидированного источника). Это самый быстрый способ.
  • Добавьте проверку через Enum.IsDefined, если есть риск получить некорректное значение. Это защитит от логических ошибок.
  • Используйте Enum.TryParse, если работаете со строковыми данными (из конфигурации, пользовательского ввода, JSON).

4. Пример безопасного преобразования

public static OrderStatus SafeConvertToStatus(int value)
{
    if (Enum.IsDefined(typeof(OrderStatus), value))
    {
        return (OrderStatus)value;
    }
    throw new ArgumentException($"Значение {value} не является допустимым статусом заказа");
}

// Использование:
try
{
    OrderStatus status = SafeConvertToStatus(2);
    Console.WriteLine(status); // Processing
}
catch (ArgumentException ex)
{
    Console.WriteLine(ex.Message);
}

Этот подход сочетает производительность cast'а с защитой от невалидных данных.

<<>>

Альтернативный подход: обобщённый метод-расширение

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

public static class EnumExtensions
{
    public static T ToEnum<T>(this int value) where T : Enum
    {
        if (Enum.IsDefined(typeof(T), value))
        {
            return (T)(object)value;
        }
        throw new ArgumentException($"Значение {value} не определено в перечислении {typeof(T).Name}");
    }
}

// Использование:
int id = 3;
OrderStatus status = id.ToEnum<OrderStatus>();
Console.WriteLine(status); // Shipped

Плюсы этого подхода:

  • Универсальность — работает для любых enum'ов.
  • Читаемый синтаксис: intValue.ToEnum<MyEnum>().
  • Автоматическая проверка на валидность.

Минусы:

  • Небольшое снижение производительности из-за boxing (упаковки в object).
  • Требуется .NET Framework 4.5+ или .NET Core для ограничения where T : Enum.

Если производительность критична (например, в цикле на миллион итераций), лучше использовать прямое приведение + Enum.IsDefined. Для обычного кода такой метод-расширение — отличное решение, повышающее читаемость и безопасность.