using System.Collections.Generic; using System.ComponentModel; using System.Reflection; namespace System { internal static class EnumUtil { public static void CheckIsEnum(bool checkHasFlags = false) { if (!typeof(T).IsEnum) throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum"); if (checkHasFlags && !IsFlags()) throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute"); } public static bool IsFlags() => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)); public static void CheckHasValue(T value, string argName = null) { CheckIsEnum(); if (IsFlags()) { var allFlags = 0L; foreach (T flag in Enum.GetValues(typeof(T))) allFlags |= Convert.ToInt64(flag); if ((allFlags & Convert.ToInt64(value)) != 0L) return; } else if (Enum.IsDefined(typeof(T), value)) return; throw new InvalidEnumArgumentException(argName ?? "value", Convert.ToInt32(value), typeof(T)); } public static byte BitPosition(this T flags) where T : struct, IConvertible { CheckIsEnum(true); var flagValue = Convert.ToInt64(flags); if (flagValue == 0) throw new ArgumentException("The flag value is zero and has no bit position."); var r = Math.Log(flagValue, 2); if (r % 1 > 0) throw new ArithmeticException("The flag value has more than a single bit set."); return Convert.ToByte(r); } public static bool IsFlagSet(this T flags, T flag) where T : struct, IConvertible { CheckIsEnum(true); var flagValue = Convert.ToInt64(flag); return (Convert.ToInt64(flags) & flagValue) == flagValue; } public static bool IsValidFlagValue(this T flags) where T : struct, IConvertible { CheckIsEnum(true); var found = 0L; foreach (T flag in Enum.GetValues(typeof(T))) { if (flags.IsFlagSet(flag)) found |= Convert.ToInt64(flag); } return found == Convert.ToInt64(flags); } public static void SetFlags(ref T flags, T flag, bool set = true) where T : struct, IConvertible { CheckIsEnum(true); var flagsValue = Convert.ToInt64(flags); var flagValue = Convert.ToInt64(flag); if (set) flagsValue |= flagValue; else flagsValue &= (~flagValue); flags = (T)Enum.ToObject(typeof(T), flagsValue); } public static T SetFlags(this T flags, T flag, bool set = true) where T : struct, IConvertible { var ret = flags; SetFlags(ref ret, flag, set); return ret; } public static T ClearFlags(this T flags, T flag) where T : struct, IConvertible => flags.SetFlags(flag, false); public static IEnumerable GetFlags(this T value) where T : struct, IConvertible { CheckIsEnum(true); foreach (T flag in Enum.GetValues(typeof(T))) { if (value.IsFlagSet(flag)) yield return flag; } } public static T CombineFlags(this IEnumerable flags) where T : struct, IConvertible { CheckIsEnum(true); long lValue = 0; foreach (var flag in flags) { var lFlag = Convert.ToInt64(flag); lValue |= lFlag; } return (T)Enum.ToObject(typeof(T), lValue); } public static string GetDescription(this T value) where T : struct, IConvertible { CheckIsEnum(); var name = Enum.GetName(typeof(T), value); if (name != null) { var field = typeof(T).GetField(name); if (field != null) { var attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; if (attr != null) { return attr.Description; } } } return null; } /// /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object or returns the value of . If is undefined, it returns the first declared item in the enumerated type. /// /// The enumeration type to which to convert . /// The string representation of the enumeration name or underlying value to convert. /// true to ignore case; false to consider case. /// The default value. /// An object of type whose value is represented by value. public static TEnum TryParse(string value, bool ignoreCase = false, TEnum defaultVal = default(TEnum)) where TEnum : struct, IConvertible { CheckIsEnum(); try { return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); } catch { } if (!Enum.IsDefined(typeof(TEnum), defaultVal)) { var v = Enum.GetValues(typeof(TEnum)); if (v != null && v.Length > 0) return (TEnum)v.GetValue(0); } return defaultVal; } } }