Masalah kinerja
Jika Anda ingin kinerja yang lebih baik, inilah cara yang harus dilakukan:
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");
}
}
}
Mengapa ini memiliki kinerja yang lebih baik?
Karena metode bawaan semua menggunakan kode yang sangat mirip dengan ini kecuali mereka juga menjalankan banyak kode lain yang tidak kami pedulikan . Kode Enum C # cukup mengerikan pada umumnya.
Kode di atas telah Linq-ified dan efisien sehingga hanya berisi bit yang kita pedulikan.
Mengapa kode bawaan lambat?
Pertama tentang Enum.ToString () -vs- Enum.GetName (..)
Selalu gunakan yang terakhir. (Atau lebih baik lagi, seperti yang akan menjadi jelas di bawah ini.)
ToString () menggunakan yang terakhir secara internal, tetapi sekali lagi, juga melakukan banyak hal lain yang tidak kita inginkan, misalnya mencoba untuk menggabungkan bendera, mencetak angka dll. Kami hanya tertarik pada konstanta yang didefinisikan di dalam enum.
Enum.GetName mendapatkan semua bidang, membuat array string untuk semua nama, menggunakan ToUInt64 di atas pada semua RawConstantValues mereka untuk membuat array UInt64 dari semua nilai, mengurutkan kedua array berdasarkan nilai UInt64, dan akhirnya mendapatkan nama dari array nama dengan melakukan BinarySearch di array UInt64 untuk menemukan indeks nilai yang kita inginkan.
... dan kemudian kita membuang bidang dan array yang disortir pergi menggunakan nama itu untuk menemukan bidang lagi.
Satu kata: "Ugh!"