EnumUtils.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. using System.Globalization;
  2. namespace MeloongCore;
  3. public static class EnumUtils {
  4. /// <summary>
  5. /// 获取枚举的所有值。
  6. /// </summary>
  7. private static IEnumerable<T> GetAllValues<T>() where T : struct, Enum
  8. => Enum.GetValues(typeof(T)).Cast<T>();
  9. /// <summary>
  10. /// 将字符串转换为枚举。
  11. /// 支持枚举名或枚举序数;若为空字符串或 <see langword="null"/> 则返回 0。
  12. /// 转换失败会抛出异常。
  13. /// </summary>
  14. public static T FromString<T>(string? value) where T : struct, Enum {
  15. if (string.IsNullOrEmpty(value)) {
  16. return (T) Enum.ToObject(typeof(T), 0);
  17. } else if (double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out var number)) {
  18. return (T) Enum.ToObject(typeof(T), Convert.ToInt64(number));
  19. } else {
  20. return (T) Enum.Parse(typeof(T), value, true);
  21. }
  22. }
  23. public static bool HasFlagF<T>(this T value, T flag) where T : struct, Enum
  24. => value.HasFlag(flag) && !EqualityComparer<T>.Default.Equals(flag, default);
  25. /// <summary>
  26. /// 对于具有 <see cref="FlagsAttribute"/> 的枚举,返回其所有 Flag 值。
  27. /// 建议仅对没有极端值的正数枚举使用。
  28. /// </summary>
  29. /// <remarks>
  30. /// 会跳过:0、非 2 的幂的值、不在枚举值中的数、组合值、对应同一个枚举项的多个别名。
  31. /// </remarks>
  32. public static List<T> GetAllFlags<T>() where T : struct, Enum {
  33. if (allFlagsCache.TryGetValue(typeof(T), out var cached)) return cached.Cast<T>().ToList();
  34. if (!typeof(T).IsDefined(typeof(FlagsAttribute), inherit: false)) throw new ArgumentException($"枚举 {typeof(T).FullName} 没有定义 FlagsAttribute。");
  35. var flags = new List<T>();
  36. foreach (var element in EnumUtils.GetAllValues<T>().Distinct()) {
  37. var number = Convert.ToInt64(element, CultureInfo.InvariantCulture);
  38. if (number == 0 || (number & (number - 1)) != 0) continue; // 跳过 0 和非 2 的幂的值
  39. flags.Add(element);
  40. }
  41. allFlagsCache[typeof(T)] = flags.Cast<Enum>().ToList();
  42. return flags;
  43. }
  44. private static readonly ConcurrentDictionary<Type, List<Enum>> allFlagsCache = new();
  45. }