El rendimiento importa
Si desea un mejor rendimiento, este es el camino a seguir:
public static class AdvancedEnumExtensions
{
/// <summary>
/// Gets the custom attribute <typeparamref name="T"/> for the enum constant, if such a constant is defined and has such an attribute; otherwise null.
/// </summary>
public static T GetCustomAttribute<T>(this Enum value) where T : Attribute
{
return GetField(value)?.GetCustomAttribute<T>(inherit: false);
}
/// <summary>
/// Gets the FieldInfo for the enum constant, if such a constant is defined; otherwise null.
/// </summary>
public static FieldInfo GetField(this Enum value)
{
ulong u64 = ToUInt64(value);
return value
.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
.Where(f => ToUInt64(f.GetRawConstantValue()) == u64)
.FirstOrDefault();
}
/// <summary>
/// Checks if an enum constant is defined for this enum value
/// </summary>
public static bool IsDefined(this Enum value)
{
return GetField(value) != null;
}
/// <summary>
/// Converts the enum value to UInt64
/// </summary>
public static ulong ToUInt64(this Enum value) => ToUInt64((object)value);
private static ulong ToUInt64(object value)
{
switch (Convert.GetTypeCode(value))
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return unchecked((ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture));
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Char:
case TypeCode.Boolean:
return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
default: throw new InvalidOperationException("UnknownEnumType");
}
}
}
¿Por qué tiene esto un mejor rendimiento?
Debido a que todos los métodos incorporados usan código muy similar a este, excepto que también ejecutan un montón de otro código que no nos importa . El código Enum de C # es bastante horrible en general.
El código anterior se ha simplificado y simplificado para que solo contenga los bits que nos interesan.
¿Por qué el código incorporado es lento?
Primero con respecto a Enum.ToString () -vs- Enum.GetName (..)
Siempre usa este último. (O mejor aún, tampoco, como se verá más adelante).
ToString () usa este último internamente, pero de nuevo, también hace un montón de otras cosas que no queremos, por ejemplo, intenta combinar banderas, imprimir números, etc. Solo nos interesan las constantes definidas dentro de la enumeración.
Enum.GetName a su vez obtiene todos los campos, crea una matriz de cadenas para todos los nombres, usa el ToUInt64 anterior en todos sus RawConstantValues para crear una matriz UInt64 de todos los valores, clasifica ambas matrices de acuerdo con el valor UInt64 y finalmente obtiene el nombre de la matriz de nombres haciendo una BinarySearch en la matriz UInt64 para encontrar el índice del valor que queríamos.
... y luego tiramos los campos y las matrices ordenadas usan ese nombre para encontrar el campo nuevamente.
Una palabra: "¡Uf!"