Respuestas:
De una cadena:
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 un int:
YourEnum foo = (YourEnum)yourInt;
Actualizar:
Del número también puedes
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
var result = Enum.TryParse(yourString, out yourEnum)
hoy en día (y verificar el resultado para determinar si la conversión falló).
Enum.Parse
true
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Solo échalo:
MyEnum e = (MyEnum)3;
Puede verificar si está dentro del rango usando Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined
, tenga en cuenta que puede ser peligroso: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefined
para verificar los valores de entrada, te vuelves vulnerable a las personas que agregan nuevos valores de enumeración más tarde que pasarían un IsDefined
cheque (ya que el nuevo el valor existe en el nuevo código), pero que podría no funcionar con el código original que escribió. Por lo tanto, es más seguro especificar explícitamente los valores de enumeración que su código puede manejar.
Alternativamente, use un método de extensión en lugar de una línea:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Uso:
Color colorEnum = "Red".ToEnum<Color>();
O
string color = "Red";
var colorEnum = color.ToEnum<Color>();
System.String
parece contaminación del espacio de nombres
Creo que para obtener una respuesta completa, las personas deben saber cómo funcionan las enumeraciones internamente en .NET.
Como funcionan las cosas
Una enumeración en .NET es una estructura que asigna un conjunto de valores (campos) a un tipo básico (el valor predeterminado es int
). Sin embargo, en realidad puede elegir el tipo integral al que se asigna su enumeración:
public enum Foo : short
En este caso, la enumeración se asigna al short
tipo de datos, lo que significa que se almacenará en la memoria como un corto y se comportará como un corto cuando lo emite y usa.
Si lo mira desde un punto de vista de IL, una enumeración (normal, int) se ve así:
.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__
}
Lo que debería llamar su atención aquí es que value__
se almacena por separado de los valores de enumeración. En el caso de la enumeración Foo
anterior, el tipo de value__
es int16. Básicamente, esto significa que puede almacenar lo que quiera en una enumeración, siempre que los tipos coincidan .
En este punto, me gustaría señalar que System.Enum
es un tipo de valor, lo que básicamente significa que BarFlag
ocupará 4 bytes en la memoria y Foo
ocupará 2, por ejemplo, el tamaño del tipo subyacente (en realidad es más complicado que eso, pero Oye...).
La respuesta
Entonces, si tiene un número entero que desea asignar a una enumeración, el tiempo de ejecución solo tiene que hacer 2 cosas: copiar los 4 bytes y nombrarlo de otra manera (el nombre de la enumeración). La copia está implícita porque los datos se almacenan como tipo de valor; esto básicamente significa que si usa código no administrado, simplemente puede intercambiar enumeraciones y enteros sin copiar datos.
Para que sea seguro, creo que es una buena práctica saber que los tipos subyacentes son iguales o implícitamente convertibles y garantizar que existan los valores de enumeración (¡no están marcados de forma predeterminada!).
Para ver cómo funciona esto, prueba el siguiente 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();
}
Tenga en cuenta que el casting e2
también funciona. Desde la perspectiva del compilador anterior, esto tiene sentido: el value__
campo simplemente se llena con 5 o 6 y cuando se Console.WriteLine
llama ToString()
, el nombre de e1
se resuelve mientras que el nombre de e2
no lo es.
Si eso no es lo que pretendía, use Enum.IsDefined(typeof(MyEnum), 6)
para verificar si el valor que está asignando asigna a una enumeración definida.
También tenga en cuenta que soy explícito sobre el tipo subyacente de la enumeración, aunque el compilador realmente verifica esto. Estoy haciendo esto para asegurarme de no encontrarme con sorpresas en el futuro. Para ver estas sorpresas en acción, puede usar el siguiente código (en realidad, he visto que esto sucede mucho en el código de la base de datos):
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
, Arrojará (falla el desempaquetado). Si lo hace object o = (short)5;
, funcionará, porque entonces los tipos coincidirán. No se trata del rango, se trata realmente del tipo.
Tome el siguiente ejemplo:
int one = 1;
MyEnum e = (MyEnum)one;
Estoy usando este código para transmitir int a mi enumeración:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Me parece la mejor solución.
A continuación se muestra una buena clase de utilidad 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, esto es más seguro ya que devolverá un objeto sin importar qué:
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;
}
}
Si está listo para 4.0 .NET Framework, hay una nueva función Enum. TryParse () que es muy útil y funciona bien con el atributo [Flags]. Ver método Enum. TryParse (String, TEnum%)
Si tiene un número entero que actúa como una máscara de bits y podría representar uno o más valores en una enumeración [Banderas], puede usar este código para analizar los valores de las banderas individuales en una 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);
}
}
Tenga en cuenta que esto supone que el tipo subyacente del enum
es un entero de 32 bits con signo. Si fuera un tipo numérico diferente, tendría que cambiar el 32 codificado para reflejar los bits en ese tipo (o derivarlo programáticamente usando Enum.GetUnderlyingType()
)
Este es un método seguro de conversión seguro de enumeración de banderas:
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
lugar de struct
, lo que significa que no tenemos que depender de la verificación del tiempo de ejecución!
Para convertir una cadena a ENUM o int a ENUM constante, necesitamos usar la función Enum.Parse. Aquí hay un video de youtube https://www.youtube.com/watch?v=4nhx4VwdRDk que realmente demuestra con cadena y lo mismo aplica para int.
El código va como se muestra a continuación, donde "rojo" es la cadena y "MyColors" es el color ENUM que tiene las constantes de color.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Me alejé un poco de la pregunta original, pero encontré una respuesta a la pregunta de desbordamiento de pila. Obtener el valor int de enum es útil. Cree una clase estática con public const int
propiedades, que le permita recopilar fácilmente un montón de int
constantes relacionadas , y luego no tener que convertirlas int
al usarlas.
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, se perderá parte de la funcionalidad de tipo enum, pero para almacenar un montón de constantes de identificación de la base de datos, parece una solución bastante ordenada.
Esto analiza enteros o cadenas a una enumeración de destino con coincidencia parcial en dot.NET 4.0 usando genéricos como en la clase de utilidad de Tawani anterior. Lo estoy usando para convertir variables de cambio de línea de comandos que pueden estar incompletas. Como una enumeración no puede ser nula, lógicamente debe proporcionar un valor predeterminado. Se puede llamar así:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
Aquí está el 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: La pregunta era sobre números enteros, que nadie mencionó también se convertirá explícitamente en Enum. TryParse ()
Desde una cadena: (Enum.Parse está desactualizado, use Enum. TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
El siguiente es un método de extensión ligeramente mejor
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;
}
En mi caso, necesitaba devolver la enumeración de un servicio WCF. También necesitaba un nombre descriptivo, no solo el enum.ToString ().
Aquí está mi clase 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;
}
}
Aquí está el método de extensión que obtiene la descripción de la enumeración.
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();
}
}
Implementación:
return EnumMember.ConvertToList<YourType>();
Ya no sé de dónde saco la parte de esta extensión de enumeración, pero es de stackoverflow. ¡Lo siento por esto! Pero tomé este y lo modifiqué para enumeraciones con Flags. Para las enumeraciones con Flags hice esto:
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;
}
}
Ejemplo:
[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;
Debería incorporar algún tipo de relajación coincidente para ser más 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 prueba
[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 formas de emitir desde y hacia 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);
}
}
Puede ayudarlo a convertir cualquier dato de entrada a la enumeración deseada por el usuario . Supongamos que tiene una enumeración como la siguiente, que por defecto es int . Agregue un valor predeterminado al principio de su enumeración. Que se utiliza en el método de ayuda cuando no se encuentra una coincidencia con el 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: Aquí trato de analizar el valor en int, porque enum es por defecto int Si define enum como este, que es el tipo de byte .
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
Debe cambiar el análisis en el método auxiliar de
int.TryParse(value.ToString(), out tempType)
a
byte.TryParse(value.ToString(), out tempType)
Compruebo mi método para las siguientes 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);
Lo siento por mi ingles
Aquí es un método de extensión que se proyecta Int32
a Enum
.
Honra las banderas bit a bit incluso cuando el valor es más alto que el máximo posible. Por ejemplo, si tiene una enumeración con las posibilidades 1 , 2 y 4 , pero el int es 9 , entiende que es 1 en ausencia de un 8 . Esto le permite realizar actualizaciones de datos antes de las actualizaciones 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);
}
La forma fácil y clara de enviar un int a enum en 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));
}
}
Simplemente usa la conversión explícita Cast int to enum o enum to 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));
}
}
}
Simplemente haz lo siguiente:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
Para asegurarse de que solo emite los valores correctos y de lo contrario puede lanzar una excepción:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
Tenga en cuenta que usar IsDefined es costoso e incluso más que solo transmitir, por lo que depende de su implementación decidir si lo usa o no.
Puedes usar el método de extensión.
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);
}
}
utilizar como código de abajo
enumeración:
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
pasa si es dinámico y solo se sabrá en tiempo de ejecución, y lo que quiero es convertirEnum
?