¿Cómo convierto int a enum en C#?
¿Cómo lanzo un int
a un enum
en C#?
De un int:
YourEnum foo = (YourEnum)yourInt;
De una cadena:
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// The foo.ToString().Contains(",") check is necessary for
// enumerations marked with a [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 número:
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum), yourInt);
Simplemente tíralo:
MyEnum e = (MyEnum)3;
Compruebe si está dentro del alcance usando Enum.IsDefined
:
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Alternativamente, use un método de extensión en lugar de una sola 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>();
Creo que para obtener una respuesta completa, la gente debe 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, puedes elegir el tipo integral al que se asigna tu 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 short y se comportará como un short cuando lo transmitas y uses.
Si lo miras desde el 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 se value__
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 puedes almacenar lo que quieras 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 ey...).
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 es implícita porque los datos se almacenan como tipo de valor; esto básicamente significa que si usa código no administrado, puede simplemente intercambiar enumeraciones y números enteros sin copiar datos.
Para que sea seguro, creo que es una buena práctica saber que los tipos subyacentes son los mismos o implícitamente convertibles y garantizar que los valores de enumeración existan (¡no están marcados de forma predeterminada!).
Para ver cómo funciona esto, pruebe 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 enviar a e2
también funciona! Desde la perspectiva del compilador anterior, esto tiene sentido: el value__
campo simplemente se completa con 5 o 6 y cuando Console.WriteLine
se llama ToString()
, el nombre de e1
se resuelve mientras que el nombre de e2
no.
Si eso no es lo que pretendía, utilice Enum.IsDefined(typeof(MyEnum), 6)
para comprobar si el valor que está transmitiendo se 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 lo verifica. Estoy haciendo esto para asegurarme de no encontrarme con sorpresas en el futuro. Para ver estas sorpresas en acción, puedes usar el siguiente código (de hecho, 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();
}
Tomemos el siguiente ejemplo:
int one = 1;
MyEnum e = (MyEnum)one;
Estoy usando este fragmento de código para transmitir int
a mi enum
:
if (typeof(YourEnum).IsEnumDefined(valueToCast))
return (YourEnum)valueToCast;
else
{
// handle it here, if it is not defined
}
Me parece la mejor solución.