Как привести int к enum?
Как int
можно передать в enum
в С#?
Ответы
Ответ 1
Из строки:
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;
Update:
Из числа вы также можете
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
Ответ 2
Просто бросьте его:
MyEnum e = (MyEnum)3;
Вы можете проверить, находится ли он в диапазоне, используя Enum.IsDefined:
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Ответ 3
В качестве альтернативы используйте метод расширения вместо однострочного:
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>();
Ответ 4
Я думаю, чтобы получить полный ответ, люди должны знать, как enums работают внутри .NET.
Как работает материал
Перечисление в .NET - это структура, которая отображает набор значений (полей) в базовый тип (по умолчанию это int
). Тем не менее, вы можете выбрать тип интеграла, который соответствует вашему перечислению:
public enum Foo : short
В этом случае перечисление преобразуется в тип данных short
, что означает, что он будет храниться в памяти как короткий и будет вести себя как короткий, когда вы используете и используете его.
Если вы посмотрите на него с точки зрения IL, (enum, int) enum выглядит следующим образом:
.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();
}
Ответ 5
Возьмем следующий пример:
int one = 1;
MyEnum e = (MyEnum)one;
Ответ 6
Я использую этот кусок кода для преобразования int в свой список перечислений:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Я считаю это лучшим решением.
Ответ 7
Ниже приведен хороший класс утилиты для 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;
}
}
Ответ 8
Для числовых значений это безопаснее, так как он вернет объект независимо от того, что:
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;
}
}
Ответ 9
Если вы готовы к созданию 4.0 .NET, здесь есть новая функция Enum.TryParse(), которая очень полезна и хорошо работает с [Flags] атрибут. См. Метод Enum.TryParse(String, TEnum%)
Ответ 10
Если у вас есть целое число, которое действует как битовая маска и может представлять одно или несколько значений в перечислении [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()
).
Ответ 11
Иногда у вас есть объект типа MyEnum
. Как
var MyEnumType = typeof(MyEnumType);
Тогда:
Enum.ToObject(typeof(MyEnum), 3)
Ответ 12
Это безопасный метод преобразования с учетом перечисления флагов:
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;
}
Ответ 13
Чтобы преобразовать строку в ENUM или int в константу ENUM, нам нужно использовать функцию Enum.Parse. Вот видео youtube https://www.youtube.com/watch?v=4nhx4VwdRDk, которые на самом деле демонстрируются со строкой, и то же самое относится к int.
Код идет, как показано ниже, где "красный" - это строка, а "MyColors" - это цвет ENUM, который имеет цветовые константы.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Ответ 14
Слегка уйти от исходного вопроса, но я нашел ответ на вопрос Qaru Получить значение 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;
}
Очевидно, что некоторые функции типа перечисления будут потеряны, но для хранения связки констант идентификатора базы данных это выглядит как довольно аккуратное решение.
Ответ 15
Это разделяет целые числа или строки на целевое перечисление с частичным совпадением в dot.NET 4.0 с использованием дженериков, таких как класс утилиты Tawani выше. Я использую его для преобразования переменных ключа командной строки, которые могут быть неполными. Поскольку перечисление не может быть нулевым, вы должны логически предоставить значение по умолчанию. Его можно назвать так:
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()
Ответ 16
Из строки: (Enum.Parse устарел, используйте Enum.TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
Ответ 17
Ниже приведен немного лучший метод расширения
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;
}
Ответ 18
В моем случае мне нужно было вернуть перечисление из службы 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>();
Ответ 19
Различные способы передачи в и из 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);
}
}
Ответ 20
Я больше не знаю, где я получаю часть этого расширения 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;
Ответ 21
Он может помочь вам преобразовать любые входные данные в желаемый перечисление пользователя. Предположим, что у вас есть перечисление вроде ниже, по умолчанию int. Добавьте сначала Default значение по умолчанию. Используется в помощниках 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;
}
}
N.B: Здесь я пытаюсь проанализировать значение в int, потому что enum по умолчанию int
Если вы определяете перечисление, подобное типу byte.
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);
извините за мой английский
Ответ 22
Здесь метод расширения, который приводит 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);
}
Ответ 23
простой и понятный способ приведения int к enum в С#:
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));
}
}
Ответ 24
Вы просто используете явное преобразование Cast int в enum или enum в 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
}
}
Ответ 25
Вы должны создать некоторую релаксацию соответствия типов, чтобы быть более устойчивой.
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();
}
Ответ 26
Вы просто делаете, как показано ниже:
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 стоит дорого и даже больше, чем просто приведение, поэтому решение о том, использовать его или нет, зависит от вашей реализации.
Ответ 27
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));
}
}
}