Convertir Enum a String

163

¿Cuál es la forma preferida de convertir una enumeración en una cadena en .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • Encadenar

¿Por qué debería preferir uno de estos sobre los demás? ¿Uno se desempeña mejor?

Eric Weilnau
fuente
10
Busqué y no pude encontrar un duplicado. Si puede proporcionar un enlace, eliminaré esta pregunta.
Eric Weilnau
1
a veces, usar una instrucción de cambio no es la mejor práctica (cuando tienes grandes enumeraciones) puedes usar Dict <> en su lugar
Guy L
1
Si desea un mejor rendimiento, puede usar la clase descrita en este artículo codeproject.com/KB/dotnet/enum.aspx . El uso se verá así Enum <YourEnum> .ToString (yourValue) o Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer
55
La codificación para no romper la fusión de puntos es el epítome de la cola que mueve al perro. Los productores de software no están pensando: "Hagamos una aplicación genial para que dotfuscator tenga algo que hacer". Dofuscator existe para ayudar a facilitar el desarrollo de SW. Si no puede hacer eso ... ¡puede!
micahhoover

Respuestas:

125

A partir de C # 6, la mejor manera de obtener el nombre de una enumeración es el nuevo nameofoperador:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

Esto funciona en tiempo de compilación, con la enumeración reemplazada por la cadena en el resultado compilado, lo que a su vez significa que esta es la forma más rápida posible.

Cualquier uso de nombres de enumeración interfiere con la ofuscación de código, si considera que la ofuscación de nombres de enumeración merece la pena o es importante, esa es probablemente una pregunta completamente diferente.

Keith
fuente
11
Esto merece más atención. No obstante la limitación obvia, es decir, el requisito de entrada en tiempo de compilación. En mi opinión, esto debería preferirse siempre que sea posible . 'Renombrar' y 'encontrar todas las referencias' también lo tienen en cuenta, evitando potencialmente cadenas mágicas y constantes duplicadas.
Timo
1
Entonces, ¿no funcionará cuando el valor de enumeración se defina en tiempo de ejecución? Ej: MyEnum variableEnum; variableEnum = setEnumValueMethod (); nameof (variableEnum);
Maxter
1
@Maxter no, como nameof(variableEnum)será "variableEnum". Refleja (en tiempo de construcción) el nombre del campo / propiedad / parámetro / variable, no el valor .
Keith
S.M. desafortunadamente no funciona si haces esto: var someEnumvalue = SomeEnum.FooBar; nameof (someEnumvalue);
Squbly
@Sí, sí, eso volverá "someEnumValue", mientras que tendrías que nameof(SomeEnum.FooBar)hacerlo "FooBar".
Keith
93

Trabaja para nuestro proyecto ...

public static String convertToString(this Enum eff)
{
    return Enum.GetName(eff.GetType(), eff);
}

public static EnumType converToEnum<EnumType>(this String enumValue)  
{
    return (EnumType) Enum.Parse(typeof(EnumType), enumValue);
}
Sumtraveller
fuente
77
Enum.GetName toma el valor como un argumento de objeto. Esto significa que el valor estará encuadrado y esto desperdiciará recursos de CPU en la asignación y en la recolección de basura. Si esto se hace mucho tiempo, Enum.GetName tendrá un rendimiento mucho menor que el almacenamiento en caché de los valores en un diccionario y la búsqueda del nombre allí.
Corrió
@Ran, ¿cuál es la solución, cuál usar en su lugar?
shaijut
Esta debería ser la respuesta
Squbly
hace que mi proyecto sea más lento toString () es más rápido.
d2k2
29

En mis pruebas, Enum.GetNamefue más rápido y con un margen decente. Internamente ToStringllamadas Enum.GetName. Desde la fuente de .NET 4.0, lo esencial:

public override String ToString()
{
     return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
}

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
    {
        String retval = GetName(eT, value); //<== the one
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else
    {
        return InternalFlagsFormat(eT, value);
    }
}

No puedo decir que esa sea la razón, pero las pruebas indican que una es más rápida que la otra. Ambas llamadas involucran boxeo (de hecho, son llamadas de reflexión, básicamente estás recuperando nombres de campo) y pueden ser lentas para tu gusto.

Configuración de prueba : enumeración con 8 valores, no. de iteraciones = 1000000

Resultado : Enum.GetName => 700 ms, ToString => 2000 ms

Si la velocidad no es notable, no me importaría y lo usaría, ToStringya que ofrece una llamada mucho más limpia. Contraste

Enum.GetName(typeof(Bla), value)

con

value.ToString()
nawfal
fuente
25

Enum.GetName (...)

Este es el método más elegante que está destinado para ello.

var enumValueString = Enum.GetName(typeof (MyEnum), MyEnum.MyValue);

Aunque no veo ningún problema con las llamadas, .ToString()ya que es simplemente más corto.

var enumValueString = MyEnum.MyValue.ToString();

Con la nueva sintaxis de C # 6 puede usar:

nameof(MyEnum.MyValue)
Andrei
fuente
20

Todos estos terminan internamente llamando a un método llamado InternalGetValueAsString. La diferencia entre ToStringy GetNamesería que GetNameprimero tiene que verificar algunas cosas:

  1. El tipo que ingresó no es nulo.
  2. El tipo que ingresó es, de hecho, una enumeración.
  3. El valor que ingresó no es nulo.
  4. El valor que ingresó es de un tipo que una enumeración puede usar realmente como su tipo subyacente, o del tipo de la enumeración misma. Se utiliza GetTypeen el valor para verificar esto.

.ToStringno tiene que preocuparse por ninguno de estos problemas anteriores, porque se llama en una instancia de la clase en sí, y no en una versión aprobada, por lo tanto, debido a que el .ToStringmétodo no tiene los mismos problemas de verificación Como los métodos estáticos, concluiría que .ToStringes la forma más rápida de obtener el valor como una cadena.

David Morton
fuente
2
¿Dónde revisaste esto? ¿Cuál fue la versión de ensamblaje? Obtengo resultados muy diferentes.
nawfal
17

Lo mejor que puedo encontrar es esta pregunta no relacionada en MSDN , que contiene un fragmento XML que responde a esta pregunta. Cualquiera de estos métodos comparte el mismo defecto: llaman enum.toString(), que no funciona correctamente cuando se utiliza Dotfuscation . Otras preocupaciones parecen estar relacionadas con el boxeo indirecto (GetName y Format). Desafortunadamente, no puedo encontrar ninguna razón de rendimiento para usar cualquiera de los anteriores.

Parafraseando desde el fragmento xml ,

Pasar una enumeración en caja a string.Format () o cualquier otra función puede provocar que enum.ToString()se llame. Esto causará problemas al Dotfuscating. No se debe utilizar enum.ToString(), enum.GetNames(), enum.GetName(), enum.Format()o enum.Parse()para convertir una enumeración en una cadena. En su lugar, use una declaración de cambio y también internacionalice los nombres si es necesario.

jpaugh
fuente
16

Enum.GetName()

Format()es realmente una envoltura GetName()con alguna funcionalidad de formato (o InternalGetValueAsString()para ser exactos). ToString()es más o menos lo mismo que Format(). Creo que GetName()es la mejor opción, ya que es totalmente obvio lo que hace para cualquiera que lea la fuente.

Tamas Czinege
fuente
8

Creo un método de extensión "Descripción" y lo adjunto a la enumeración para que pueda obtener un nombre realmente fácil de usar que incluya espacios y mayúsculas. Nunca me ha gustado usar el valor enum como texto visualizable porque es algo que los desarrolladores usamos para crear código más legible. No está destinado a la visualización de la interfaz de usuario. Quiero poder cambiar la interfaz de usuario sin pasar y cambiar las enumeraciones por todas partes.

Bailes Con Bamboo
fuente
6

No sé cuál es el método "preferido" (pregunte a 100 personas y obtenga 100 opiniones diferentes), pero haga lo que sea más simple y lo que funcione. GetNamefunciona pero requiere muchas más pulsaciones de teclas. ToString()Parece que hace el trabajo muy bien.

Perry Neal
fuente
1

Para aficionados a VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
GlennG
fuente
0

Esto también funcionaría.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
Nic
fuente
0

ToString()da el resultado más obvio desde una perspectiva de legibilidad, mientras que el uso Enum.GetName()requiere un poco más de análisis mental para comprender rápidamente lo que está tratando de hacer (a menos que vea el patrón todo el tiempo).

Desde un punto de vista de rendimiento puro, como ya se proporcionó en la respuesta de @ nawfal, Enum.GetName()es mejor.

Sin embargo, si el rendimiento es realmente su objetivo, sería aún mejor proporcionar una búsqueda de antemano (utilizando un diccionario o alguna otra asignación).

En C ++ / CLI, esto se vería así

Dictionary<String^, MyEnum> mapping;
for each (MyEnum field in Enum::GetValues(MyEnum::typeid))
{
    mapping.Add(Enum::GetName(MyEnum::typeid), field);
}

Comparación utilizando una enumeración de 100 elementos y 1000000 iteraciones:

Enum.GetName: ~ 800ms
.ToString (): ~ 1600ms
Mapeo del diccionario: ~ 250ms

John Go-Soco
fuente
-2

Simple: enumerar nombres en una lista:

List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()
Brian
fuente
Hola @Brian, no creo que necesites transmitir el resultado de GetNames ()
Nic