Відповіді:
З рядка:
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);
var result = Enum.TryParse(yourString, out yourEnum)сьогодні (і перевірити результат, щоб визначити, чи не вдалося перетворити).
Enum.Parseбути нечутливими до регістру, додавши trueдо виклику значення параметра:YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Просто киньте його:
MyEnum e = (MyEnum)3;
Ви можете перевірити, чи знаходиться він у діапазоні, використовуючи Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined, майте на увазі, що це може бути небезпечно: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefinedдля перевірки вхідних значень, ви залишаєте себе вразливим до людей, додаючи нові значення перерахунків пізніше, які пройдуть IsDefinedперевірку (оскільки нові значення існує в новому коді), але це може не працювати з оригінальним кодом, який ви написали. Тому безпечніше чітко вказати значення перерахунків, з якими може працювати ваш код.
Крім того, використовуйте метод розширення замість однолінійного:
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>();
System.Stringвиглядає як забруднення простору імен
Я думаю, щоб отримати повну відповідь, люди повинні знати, як енуми працюють у .NET.
Як працює матеріал
Перерахунок у .NET - це структура, яка відображає набір значень (полів) до базового типу (типовим є int). Однак ви можете фактично вибрати інтегральний тип, на який відображається ваш перелік:
public enum Foo : short
У цьому випадку перерахунок відображається на shortтип даних, а це означає, що він буде зберігатися в пам'яті як короткий і буде вести себе як короткий при передачі та використанні.
Якщо ви дивитесь на це з точки зору ІЛ, перерахунок (нормальний, внутрішній) виглядає так:
.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__зберігається окремо від значень enum. У випадку перерахунку Fooвище тип value__int16. Це в основному означає, що ви можете зберігати все, що завгодно, в кількості, доки типи відповідають .
На цьому етапі я хотів би зазначити, що System.Enumце тип значення, який в основному означає, що BarFlagвін займе 4 байти в пам'яті і Fooзайме 2 - наприклад, розмір базового типу (це насправді складніше, ніж це, але гей ...).
Відповідь
Отже, якщо у вас є ціле число, яке ви хочете зіставити на enum, час виконання повинен виконати лише 2 речі: скопіювати 4 байти та назвати його чимось іншим (назва enum). Копіювання є неявним, оскільки дані зберігаються як тип значення - це в основному означає, що якщо ви використовуєте некерований код, ви можете просто обмінятись перерахуваннями і цілими числами без копіювання даних.
Щоб зробити це безпечним, я вважаю, що найкраща практика знати, що основні типи однакові або неявно конвертовані та забезпечити існування значень enum (вони не перевіряються за замовчуванням!).
Щоб побачити, як це працює, спробуйте наступний код:
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();
}
int! = short, Він буде кинутий (вимикання не працює). Якщо ви це зробите object o = (short)5;, це спрацює, бо тоді типи будуть відповідати. Мова не про асортимент, це справді про тип.
Візьмемо такий приклад:
int one = 1;
MyEnum e = (MyEnum)one;
Я використовую цей фрагмент коду, щоб подати int моєму перерахунку:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Я вважаю це найкращим рішенням.
Нижче представлений приємний клас корисності для 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;
}
}
Для числових значень це безпечніше, оскільки він поверне об'єкт незалежно від того, що:
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;
}
}
Якщо ви готові до версії 4.0 .NET Framework, є нова функція Enum.TryParse (), яка дуже корисна і добре грає з атрибутом [Flags]. Дивіться метод Enum.TryParse (Рядок, TEnum%)
Якщо у вас є ціле число, яке виступає в якості бітової маски і могло представляти одне або більше значень у переліку [Флаги], ви можете використовувати цей код для розбору окремих значень прапора у списку:
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())
Це прапор переліку безпечних методів перерахування прапорів:
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;
}
Enumзамість цього struct, тобто ми не повинні покладатися на перевірку часу виконання!

Для перетворення рядка в ENUM або int в ENUM константу нам потрібно використовувати функцію Enum.Parse. Ось відео https://www.youtube.com/watch?v=4nhx4VwdRDk на YouTube, яке фактично демонструє, є рядком і те саме стосується int.
Код йде так, як показано нижче, де "червоний" є рядком, а "MyColors" - кольором ENUM, який має кольорові константи.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Трохи відходячи від початкового запитання, але я знайшов відповідь на питання Stack Overflow Отримати значення int від enum корисно. Створіть статичний клас із 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 буде втрачена, але для зберігання купи констант ідентифікаторів бази даних це здається досить акуратним рішенням.
Це аналізує цілі числа чи рядки до цільового перерахунку з частковим узгодженням у dot.NET 4.0, використовуючи дженерики, як у клас утиліти Тавані вище. Я використовую його для перетворення змінних командного рядка, які можуть бути неповними. Оскільки enum не може бути нульовим, вам слід логічно вказати значення за замовчуванням. Це можна назвати так:
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;
}
}
}
}
}
FYI: Питання стосувалося цілих чисел, про які ніхто не згадував також явно перетворить в Enum.TryParse ()
З рядка: (Enum.Parse застарів, використовуйте Enum.TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
Далі йде трохи кращий спосіб розширення
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;
}
У моєму випадку мені потрібно було повернути перерахунок із служби 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;
}
}
Ось метод розширення, який отримує Опис від 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>();
Я більше не знаю, звідки я беру частину цього розширення enum, але це від 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;
Вам слід створити відповідні релакси типу, щоб бути більш надійними.
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();
}
Різні способи подачі на та з нього 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 . Припустимо, у вас є enum на зразок нижче, який за замовчуванням int . Будь ласка, додайте значення за замовчуванням спочатку вашого перерахунку. Застосовується у помічниках, коли не знайдено відповідності з вхідним значенням.
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;
}
}
NB: Тут я намагаюся проаналізувати значення на int, тому що enum за замовчуванням int Якщо ви визначаєте enum, як цей, який є тип байта .
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);
Вибачте за мою англійську
Ось метод розширення , який кидає 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);
}
простий і зрозумілий спосіб введення int до перерахунку в 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 для перерахунку або перерахування до 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
}
}
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));
}
}
}
Вам просто подобається нижче:
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 коштує дорого і навіть більше, ніж просто кастинг, тому вирішити використовувати його чи ні залежить від вашої реалізації.
Можна використовувати метод розширення.
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);
}
}
використовувати, як нижче код
перерахувати:
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>();
YourEnumце динамічно і стане відомо лише під час виконання, і що я хочу це перетворитиEnum?