Как преобразовать int в enum в C#?
Чтобы привести int к enum в C#, можно использовать явное приведение типов (YourEnumType)intValue или метод Enum.ToObject(). Явное приведение является наиболее простым подходом, когда тип enum известен на этапе компиляции, в то время как Enum.ToObject() полезен в сценариях, когда тип enum определяется во время выполнения.
Содержание
- Явное приведение типов
- Метод Enum.ToObject()
- Вопросы безопасности
- Лучшие практики
- Продвинутые сценарии
- Полный пример
Явное приведение типов
Наиболее распространенным и простым способом приведения int к enum в C# является использование явного приведения типов:
public enum Status
{
Active = 1,
Inactive = 2,
Pending = 3
}
int statusCode = 2;
Status status = (Status)statusCode; // Status.Inactive
Ключевые моменты о явном приведении:
- Ручное преобразование: При преобразовании int в enum мы выполняем явное приведение и сообщаем компилятору, что принимаем риски несовместимости этих типов источник.
- Безопасность компилятора: Принудительное явное преобразование int заставляет компилятор рассматривать enum как специальный тип - один из многих вариантов, а не как целое число источник.
- Синтаксис:
YourEnumType enumVariable = (YourEnumType)intValue;
// Базовый пример
public enum Day
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7
}
int dayNumber = 3;
Day day = (Day)dayNumber; // Day.Wednesday
Метод Enum.ToObject()
Когда вам нужно работать с типами enum, определяемыми во время выполнения, Enum.ToObject() является подходящим выбором:
Type enumType = typeof(Status);
int numericValue = 2;
object boxedEnumValue = Enum.ToObject(enumType, numericValue);
Status status = (Status)boxedEnumValue; // Status.Inactive
Когда использовать Enum.ToObject():
- Сценарии времени выполнения: Может использоваться в случаях, когда вам нужно динамически получать значения enum (или, возможно, метаданные (атрибуты), прикрепленные к значениям enum) источник.
- Обобщенные методы: Полезно для создания обобщенных методов расширения:
public static T ToEnum<T>(this int value) where T : struct
{
return (T)Enum.ToObject(typeof(T), value);
}
// Использование
Status status = 2.ToEnum<Status>(); // Status.Inactive
Вопросы безопасности
При приведении целых чисел к enum следует учитывать безопасность, чтобы избежать исключений времени выполнения:
Enum.IsDefined() для валидации
Перед приведением можно проверить, соответствует ли целочисленное значение определенному члену enum:
int statusCode = 5;
if (Enum.IsDefined(typeof(Status), statusCode))
{
Status status = (Status)statusCode;
}
else
{
// Обработка недопустимого значения enum
Console.WriteLine("Недопустимый код статуса");
}
Почему валидация важна:
- Без валидации приведение целого числа, не соответствующего ни одному члену enum, все равно скомпилируется и выполнится, но может вызвать неожиданное поведение в вашем приложении
- Это особенно важно при работе с пользовательским вводом или данными из внешних источников
Лучшие практики
1. Всегда валидируйте при необходимости
public static Status SafeCastToStatus(int code)
{
return Enum.IsDefined(typeof(Status), code)
? (Status)code
: throw new ArgumentException("Недопустимый код статуса");
}
2. Корректно обрабатывайте неопределенные значения
public static Status ToStatusOrDefault(int code, Status defaultValue = default)
{
try
{
return (Status)code;
}
catch
{
return defaultValue;
}
}
3. Используйте методы расширения для переиспользования
public static class EnumExtensions
{
public static T ToEnum<T>(this int value, T defaultValue = default) where T : struct
{
if (Enum.IsDefined(typeof(T), value))
{
return (T)Enum.ToObject(typeof(T), value);
}
return defaultValue;
}
}
// Использование
var status = 2.ToEnum<Status>(); // Status.Inactive
var invalidStatus = 99.ToEnum<Status>(); // default(Status)
Продвинутые сценарии
1. Обобщенное преобразование enum
public static TEnum ToEnum<TEnum>(this int value) where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!typeof(TEnum).IsEnum)
{
throw new ArgumentException("TEnum должен быть перечислимым типом");
}
if (Enum.IsDefined(typeof(TEnum), value))
{
return (TEnum)Enum.ToObject(typeof(TEnum), value);
}
// Обработка битовых флагов, если применимо
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);
if (isBitwise)
{
return (TEnum)Enum.ToObject(typeof(TEnum), value);
}
throw new ArgumentException($"Значение {value} является недопустимым для перечисления {typeof(TEnum).Name}");
}
2. Работа с nullable enum
public static TEnum? ToNullableEnum<TEnum>(this int? value) where TEnum : struct
{
if (value == null)
{
return null;
}
return value.Value.ToEnum<TEnum>();
}
Полный пример
Вот комплексный пример, демонстрирующий различные подходы:
using System;
public class Program
{
public enum UserStatus
{
Active = 1,
Inactive = 2,
Pending = 3,
Suspended = 4
}
public static void Main()
{
// Базовое явное приведение
int statusValue = 3;
UserStatus status1 = (UserStatus)statusValue;
Console.WriteLine($"Статус 1: {status1}"); // Статус 1: Pending
// Использование Enum.ToObject
UserStatus status2 = (UserStatus)Enum.ToObject(typeof(UserStatus), 4);
Console.WriteLine($"Статус 2: {status2}"); // Статус 2: Suspended
// Безопасное приведение с валидацией
int userInput = 5;
UserStatus? safeStatus = SafeCastToUserStatus(userInput);
Console.WriteLine($"Безопасный статус: {safeStatus ?? UserStatus.Active}"); // Безопасный статус: Active
// Подход с методом расширения
var status3 = 2.ToEnum<UserStatus>();
Console.WriteLine($"Статус 3: {status3}"); // Статус 3: Inactive
}
public static UserStatus? SafeCastToUserStatus(int value)
{
return Enum.IsDefined(typeof(UserStatus), value)
? (UserStatus)value
: null;
}
}
// Метод расширения для более чистого синтаксиса
public static class EnumExtensions
{
public static T ToEnum<T>(this int value, T defaultValue = default) where T : struct
{
return Enum.IsDefined(typeof(T), value)
? (T)Enum.ToObject(typeof(T), value)
: defaultValue;
}
}
Заключение
Приведение int к enum в C# является простым с помощью явного приведения, но важны следующие соображения:
- Используйте явное приведение для простых сценариев, когда тип enum известен на этапе компиляции:
(YourEnumType)intValue - Применяйте Enum.ToObject() для динамического определения типа:
Enum.ToObject(enumType, intValue) - Всегда валидируйте при работе с внешними данными с помощью
Enum.IsDefined(), чтобы предотвратить проблемы времени выполнения - Создавайте методы расширения для более чистого и переиспользуемого кода
- Корректно обрабатывайте крайние случаи, такие как неопределенные значения и nullable enum
Выбор между явным приведением и Enum.ToObject() зависит от того, знаете ли вы тип enum на этапе компиляции или нужно работать с ним динамически. Оба подхода являются допустимыми, но явное приведение обычно предпочтительнее из-за своей простоты и читаемости, когда тип enum известен заранее.
Источники
- How do I cast int to enum in C#? - Stack Overflow
- C#: How to convert int to enum? – Josip Miskovic
- c# - Why enums require an explicit cast to int type? - Stack Overflow
- 2 ways to convert/cast int to enum in C# - Arun Gudelli
- c# - Casting to enum vs. Enum.ToObject - Stack Overflow
- Convert Int to Enum in C# - TutorialTeacher