Как преобразовать строку в перечисление (enum) в C#?
Использование Enum.Parse() и Enum.TryParse()
В C# есть встроенные методы для преобразования строк в перечисления. Самый простой и распространённый способ — использовать статический метод Enum.Parse() или его безопасную версию Enum.TryParse().
1. Enum.Parse() — базовый вариант
Метод Enum.Parse() принимает тип перечисления и строку, а возвращает объект типа object, который нужно явно привести к нужному перечислению:
string input = "Shipped";
OrderStatus status = (OrderStatus)Enum.Parse(typeof(OrderStatus), input);
Console.WriteLine(status); // Вывод: Shipped
Этот метод чувствителен к регистру по умолчанию. Если строка не соответствует ни одному значению или написана с другой буквой (например, "shipped"), будет выброшено исключение ArgumentException. Чтобы игнорировать регистр, добавьте третий параметр ignoreCase: true:
string input = "shipped";
OrderStatus status = (OrderStatus)Enum.Parse(typeof(OrderStatus), input, ignoreCase: true);
Console.WriteLine(status); // Вывод: Shipped
2. Enum.TryParse() — безопасный вариант (рекомендуется)
Если вы не уверены, что строка всегда корректна, лучше использовать Enum.TryParse(). Он не выбрасывает исключение, а возвращает bool — успешно ли прошло преобразование. Результат сохраняется в выходной параметр:
string input = "Cancelled";
if (Enum.TryParse(input, out OrderStatus status))
{
Console.WriteLine($"Статус: {status}");
}
else
{
Console.WriteLine("Неверный статус!");
}
По умолчанию TryParse() также чувствителен к регистру. Чтобы сделать его нечувствительным, используйте соответствующую перегрузку:
string input = "cancelled";
if (Enum.TryParse(input, ignoreCase: true, out OrderStatus status))
{
Console.WriteLine($"Статус: {status}"); // Вывод: Статус: Cancelled
}
3. Обработка числовых строк
Интересно, что Enum.TryParse() также может преобразовывать строки, содержащие числа. Например, если ваше перечисление имеет числовые значения (по умолчанию с 0), то строка "2" будет соответствовать OrderStatus.Shipped:
string input = "2";
if (Enum.TryParse(input, out OrderStatus status))
{
Console.WriteLine(status); // Вывод: Shipped
}
Это может быть как удобно, так и опасно. Если вы хотите разрешить только строковые имена, а не числа, добавьте проверку через Enum.IsDefined():
string input = "2";
if (Enum.TryParse(input, out OrderStatus status) && Enum.IsDefined(typeof(OrderStatus), status))
{
Console.WriteLine($"Корректный статус: {status}");
}
else
{
Console.WriteLine("Неверное значение");
}
4. Работа с атрибутами [Description]
Иногда строки в вашей системе могут отличаться от имён в перечислении. Например, в JSON может прийти "in_progress" вместо "Processing". В таком случае помогает атрибут Description из пространства имён System.ComponentModel:
using System.ComponentModel;
public enum OrderStatus
{
[Description("in_progress")]
Processing,
[Description("on_the_way")]
Shipped,
// ...
}
Для преобразования потребуется написать вспомогательный метод, который читает атрибут:
public static T GetEnumFromDescription<T>(string description) where T : Enum
{
foreach (var field in typeof(T).GetFields())
{
if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
{
if (attribute.Description == description)
return (T)field.GetValue(null);
}
else if (field.Name == description) // fallback на имя
{
return (T)field.GetValue(null);
}
}
throw new ArgumentException($"Строка '{description}' не найдена в {typeof(T).Name}");
}
Использование:
string input = "in_progress";
OrderStatus status = GetEnumFromDescription<OrderStatus>(input);
Console.WriteLine(status); // Вывод: Processing
Рекомендация
Для большинства случаев используйте Enum.TryParse() с параметром ignoreCase: true и дополнительной проверкой через Enum.IsDefined(), если нужно исключить числовые строки. Это даёт чистый, безопасный и читаемый код без громоздких switch.
Альтернативный подход: метод расширения (Extension Method)
Если вам часто приходится конвертировать строки в перечисления, удобно создать метод расширения для типа string. Это сделает код ещё более лаконичным:
public static class EnumExtensions
{
public static T ToEnum<T>(this string value, bool ignoreCase = true) where T : Enum
{
return (T)Enum.Parse(typeof(T), value, ignoreCase);
}
public static bool TryToEnum<T>(this string value, out T result, bool ignoreCase = true) where T : Enum
{
return Enum.TryParse(value, ignoreCase, out result);
}
}
Теперь преобразование выглядит очень просто:
string input = "delivered";
OrderStatus status = input.ToEnum<OrderStatus>();
Console.WriteLine(status); // Вывод: Delivered
// Безопасный вариант:
if (input.TryToEnum(out OrderStatus safeStatus))
{
Console.WriteLine(safeStatus);
}
Этот подход особенно полезен, когда вы работаете с большим количеством перечислений в проекте. Метод расширения инкапсулирует логику и уменьшает дублирование кода. Единственный минус — нужно помнить о возможном исключении в ToEnum(), если строка некорректна, поэтому для пользовательского ввода всегда используйте TryToEnum().
Ответов пока нет.
Войдите чтобы оставить ответ