Vấn đề hiệu suất
Nếu bạn muốn hiệu suất tốt hơn đây là con đường để đi:
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");
}
}
}
Tại sao điều này có hiệu suất tốt hơn?
Bởi vì tất cả các phương thức tích hợp đều sử dụng mã rất giống với điều này ngoại trừ chúng cũng chạy một loạt các mã khác mà chúng tôi không quan tâm . Mã Enum của C # nói chung khá kinh khủng.
Đoạn mã trên đã được Linq-ified và sắp xếp hợp lý để nó chỉ chứa các bit mà chúng ta quan tâm.
Tại sao mã tích hợp chậm?
Đầu tiên liên quan đến Enum.ToString () -vs- Enum.GetName (..)
Luôn luôn sử dụng cái sau. (Hoặc tốt hơn là không, như sẽ trở nên rõ ràng dưới đây.)
ToString () sử dụng cái sau trong nội bộ, nhưng một lần nữa, cũng thực hiện một loạt các thứ khác mà chúng tôi không muốn, ví dụ: cố gắng kết hợp cờ, in ra số, v.v. Chúng tôi chỉ quan tâm đến các hằng số được xác định bên trong enum.
Enum.GetName lần lượt lấy tất cả các trường, tạo một chuỗi chuỗi cho tất cả các tên, sử dụng ToUInt64 ở trên trên tất cả các RawConstantValues của chúng để tạo một mảng UInt64 của tất cả các giá trị, sắp xếp cả hai mảng theo giá trị UInt64 và cuối cùng lấy tên từ mảng tên bằng cách thực hiện Tìm kiếm nhị phân trong mảng UInt64 để tìm chỉ mục của giá trị chúng tôi muốn.
... Và sau đó chúng ta ném các trường và các mảng được sắp xếp sử dụng tên đó để tìm lại trường.
Một từ: "Ư!"