Respostas:
De uma sequência:
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.")
}
De um int:
YourEnum foo = (YourEnum)yourInt;
Atualizar:
Do número, você também pode
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
var result = Enum.TryParse(yourString, out yourEnum)
hoje em dia (e verificando o resultado para determinar se a conversão falhou).
Enum.Parse
true
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Basta transmitir:
MyEnum e = (MyEnum)3;
Você pode verificar se está dentro do alcance usando Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined
, lembre-se de que isso pode ser perigoso: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefined
para verificar os valores de entrada, você se deixa vulnerável a pessoas que adicionam novos valores de enum posteriormente, o que passaria em uma IsDefined
verificação (uma vez que o novo existe no novo código), mas que pode não funcionar com o código original que você escreveu. Portanto, é mais seguro especificar explicitamente os valores de enumeração que seu código pode manipular.
Como alternativa, use um método de extensão em vez de uma linha:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Uso:
Color colorEnum = "Red".ToEnum<Color>();
OU
string color = "Red";
var colorEnum = color.ToEnum<Color>();
System.String
parece poluir o espaço para nome #
Penso que para obter uma resposta completa, as pessoas precisam saber como as enums funcionam internamente no .NET.
Como as coisas funcionam
Uma enumeração no .NET é uma estrutura que mapeia um conjunto de valores (campos) para um tipo básico (o padrão é int
). No entanto, você pode realmente escolher o tipo integral para o qual sua enum mapeia:
public enum Foo : short
Nesse caso, a enumeração é mapeada para o short
tipo de dados, o que significa que será armazenado na memória como um curto e se comportará como um curto quando você o converter e usar.
Se você olhar para ele do ponto de vista da IL, um enum (normal, int) será assim:
.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__
}
O que deve chamar sua atenção aqui é que o value__
arquivo é armazenado separadamente dos valores da enumeração. No caso da enum Foo
acima, o tipo de value__
é int16. Isso basicamente significa que você pode armazenar o que quiser em uma enumeração, desde que os tipos correspondam .
Neste ponto, gostaria de salientar que System.Enum
é um tipo de valor, o que basicamente significa que BarFlag
ocupará 4 bytes na memória e Foo
ocupará 2 - por exemplo, o tamanho do tipo subjacente (na verdade é mais complicado que isso, mas Ei...).
A resposta
Portanto, se você tem um número inteiro que deseja mapear para uma enumeração, o tempo de execução precisa fazer apenas duas coisas: copiar os 4 bytes e nomeá-la de outra forma (o nome da enumeração). A cópia está implícita porque os dados são armazenados como tipo de valor - isso basicamente significa que, se você usar código não gerenciado, poderá simplesmente trocar enumerações e números inteiros sem copiar dados.
Para torná-lo seguro, acho que é uma prática recomendada saber que os tipos subjacentes são iguais ou implicitamente conversíveis e garantir que os valores da enumeração existam (eles não são verificados por padrão!).
Para ver como isso funciona, tente o seguinte código:
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();
}
Observe que a conversão para e2
também funciona! Da perspectiva do compilador acima, isso faz sentido: o value__
campo é simplesmente preenchido com 5 ou 6 e, quando Console.WriteLine
chamadas ToString()
, o nome de e1
é resolvido enquanto o nome de e2
não é.
Se não foi isso que você pretendia, use Enum.IsDefined(typeof(MyEnum), 6)
para verificar se o valor que você está convertendo é mapeado para uma enumeração definida.
Observe também que sou explícito sobre o tipo subjacente da enum, mesmo que o compilador realmente verifique isso. Estou fazendo isso para garantir que não tenha surpresas no caminho. Para ver essas surpresas em ação, você pode usar o seguinte código (na verdade, eu já vi isso acontecer muito no código do banco de dados):
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
, Será lançada (a remoção do unboxing falha). Se você o fizer object o = (short)5;
, funcionará, porque os tipos corresponderão. Não é sobre o alcance, é realmente sobre o tipo.
Veja o seguinte exemplo:
int one = 1;
MyEnum e = (MyEnum)one;
Estou usando este pedaço de código para converter int para minha enumeração:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Acho a melhor solução.
Abaixo está uma boa classe de utilitário para 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;
}
}
Para valores numéricos, isso é mais seguro, pois retornará um objeto, não importa o que:
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;
}
}
Se você estiver pronto para o 4.0 .NET Framework, há uma nova função Enum.TryParse () que é muito útil e funciona bem com o atributo [Flags]. Consulte o método Enum.TryParse (String, TEnum%)
Se você tiver um número inteiro que atue como uma máscara de bits e possa representar um ou mais valores em uma enumeração [Flags], poderá usar esse código para analisar os valores de sinalizadores individuais em uma lista:
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);
}
}
Observe que isso pressupõe que o tipo subjacente do enum
é um número inteiro de 32 bits assinado. Se fosse um tipo numérico diferente, você teria que alterar os 32 codificados permanentemente para refletir os bits desse tipo (ou derivá-lo programaticamente usando Enum.GetUnderlyingType()
)
Este é um método de conversão segura com reconhecimento de enumeração de sinalizadores:
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
não struct
, o que significa que não precisamos confiar na verificação do tempo de execução!
Para converter uma string em constante ENUM ou int em ENUM, precisamos usar a função Enum.Parse. Aqui está um vídeo do youtube https://www.youtube.com/watch?v=4nhx4VwdRDk que realmente demonstra com string e o mesmo se aplica a int.
O código segue como mostrado abaixo, onde "vermelho" é a sequência e "MyColors" é a cor ENUM que possui constantes de cores.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Afastando-me um pouco da pergunta original, mas encontrei uma resposta para a pergunta Stack Overflow Obter valor int de enum útil. Crie uma classe estática com public const int
propriedades, permitindo que você colete facilmente um monte de int
constantes relacionadas e depois não precise convertê-las ao int
usá-las.
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;
}
Obviamente, algumas das funcionalidades do tipo enum serão perdidas, mas, para armazenar um monte de constantes de identificação de banco de dados, parece uma solução bem organizada.
Isso analisa números inteiros ou seqüências de caracteres em uma enumeração de destino com correspondência parcial no dot.NET 4.0 usando genéricos como na classe de utilitário de Tawani acima. Estou usando-o para converter variáveis de opção da linha de comando que podem estar incompletas. Como uma enum não pode ser nula, você deve fornecer logicamente um valor padrão. Pode ser chamado assim:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
Aqui está o código:
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: A pergunta era sobre números inteiros, que ninguém mencionado também converterá explicitamente em Enum.TryParse ()
Em uma sequência: (Enum.Parse está desatualizado, use Enum.TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
A seguir é um método de extensão ligeiramente melhor
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;
}
No meu caso, eu precisava retornar a enumeração de um serviço WCF. Eu também precisava de um nome amigável, não apenas o enum.ToString ().
Aqui está minha classe do 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;
}
}
Aqui está o método Extension que obtém a Descrição do 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();
}
}
Implementação:
return EnumMember.ConvertToList<YourType>();
Eu não sei mais de onde eu recebo a parte dessa extensão enum, mas é do stackoverflow. Desculpe-me por isto! Mas peguei este e modifiquei-o para enumerações com Flags. Para enums com Flags, fiz o seguinte:
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;
}
}
Exemplo:
[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;
Você deve criar algum tipo de relaxamento correspondente para ser mais robusto.
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))));
}
Caso de teste
[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();
}
Diferentes maneiras de transmitir de e para 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);
}
}
Pode ajudá-lo a converter qualquer dado de entrada na enumeração desejada pelo usuário . Suponha que você tenha um enum como abaixo do qual, por padrão, int . Adicione um valor padrão no início da sua enumeração. Que é usado no método de ajuda quando não há correspondência encontrada com o valor de entrada.
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: Aqui eu tento analisar o valor em int, porque enum é por padrão int Se você definir enum como este, que é do tipo byte .
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
Você precisa alterar o método de análise no auxiliar de
int.TryParse(value.ToString(), out tempType)
para
byte.TryParse(value.ToString(), out tempType)
Verifico meu método para as seguintes entradas
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);
Desculpe pelo meu Inglês
Aqui está um método de extensão que lança Int32
a Enum
.
Ele honra sinalizadores bit a bit, mesmo quando o valor é maior que o máximo possível. Por exemplo, se você tiver um enum com as possibilidades 1 , 2 e 4 , mas o int for 9 , ele entenderá como 1 na ausência de um 8 . Isso permite que você faça atualizações de dados antes das atualizações de código.
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);
}
a maneira fácil e clara de converter um int enum em 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));
}
}
Você simplesmente usa a conversão explícita Cast int para enum ou enum para 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));
}
}
}
Você apenas faz como abaixo:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
Para se certificar de que você apenas lança os valores corretos e pode gerar uma exceção caso contrário:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
Observe que o uso de IsDefined é caro e ainda mais do que apenas a conversão, portanto, depende da sua implementação decidir usá-lo ou não.
Você pode usar o método de extensão.
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);
}
}
use como código abaixo
enum:
public enum DaysOfWeeks
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
Uso:
string Monday = "Mon";
int Wednesday = 3;
var Mon = Monday.ToEnum<DaysOfWeeks>();
var Wed = Wednesday.ToEnum<DaysOfWeeks>();
YourEnum
for dinâmico e só for conhecido em tempo de execução, e o que eu quero é converterEnum
?