¿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?
¿Cuál es la forma preferida de convertir una enumeración en una cadena en .NET 3.5?
¿Por qué debería preferir uno de estos sobre los demás? ¿Uno se desempeña mejor?
Respuestas:
A partir de C # 6, la mejor manera de obtener el nombre de una enumeración es el nuevo nameof
operador:
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.
nameof(variableEnum)
será "variableEnum"
. Refleja (en tiempo de construcción) el nombre del campo / propiedad / parámetro / variable, no el valor .
"someEnumValue"
, mientras que tendrías que nameof(SomeEnum.FooBar)
hacerlo "FooBar"
.
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);
}
En mis pruebas, Enum.GetName
fue más rápido y con un margen decente. Internamente ToString
llamadas 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, ToString
ya que ofrece una llamada mucho más limpia. Contraste
Enum.GetName(typeof(Bla), value)
con
value.ToString()
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)
Todos estos terminan internamente llamando a un método llamado InternalGetValueAsString
. La diferencia entre ToString
y GetName
sería que GetName
primero tiene que verificar algunas cosas:
GetType
en el valor para verificar esto..ToString
no 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 .ToString
método no tiene los mismos problemas de verificación Como los métodos estáticos, concluiría que .ToString
es la forma más rápida de obtener el valor como una cadena.
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 utilizarenum.ToString()
,enum.GetNames()
,enum.GetName()
,enum.Format()
oenum.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.
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.
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.
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. GetName
funciona pero requiere muchas más pulsaciones de teclas. ToString()
Parece que hace el trabajo muy bien.
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