Виконання питань має значення
Якщо ви хочете покращити продуктивність, це шлях:
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");
}
}
}
Чому це має кращі показники?
Оскільки вбудовані методи використовують код, дуже подібний до цього, за винятком того, що вони також виконують купу іншого коду, про який нам не важливо . Код Enum C # 'є загалом жахливим.
Вищеописаний код був ідентифікований Linq та впорядкований, тому він містить лише біти, про які нам важливо.
Чому вбудований код повільний?
Спочатку про Enum.ToString () -vs- Enum.GetName (..)
Завжди використовуйте останнє. (А ще краще ні те, як стане зрозуміло нижче.)
ToString () використовує останнє внутрішньо, але знову ж таки, також робить купу інших речей, які ми не хочемо, наприклад, намагається поєднувати прапори, роздрукувати числа тощо. Нас цікавлять лише константи, визначені всередині enum.
Enum.GetName отримує всі поля, створює рядковий рядок для всіх імен, використовує вищевказаний ToUInt64 для всіх своїх RawConstantValues для створення масиву всіх значень UInt64, сортує обидва масиви відповідно до значення UInt64 і нарешті отримує ім'я від масив імен, виконавши BinarySearch в масиві UInt64, щоб знайти індекс потрібного нам значення.
... а потім ми кидаємо поля та відсортовані масиви, використовуючи це ім'я, щоб знову знайти поле.
Одне слово: "Фу!"