diff --git a/Core/Extensions/EnumExtensions.cs b/Core/Extensions/EnumExtensions.cs index f1d0dd6c..2c4b34ad 100644 --- a/Core/Extensions/EnumExtensions.cs +++ b/Core/Extensions/EnumExtensions.cs @@ -9,14 +9,29 @@ namespace Vanara.Extensions /// Extensions for enumerated types. public static class EnumExtensions { + /// Gets the bit position of a flag that has a single bit, starting at 0. + /// The enumerated type. + /// The enumerated value. + /// The bit position, starting at 0, of the single bit flag specified in . + /// The flag value is zero and has no bit position. + /// The flag value has more than a single bit set. + public static byte BitPosition(this T flags) where T : struct, System.Enum + { + CheckHasFlags(); + 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 (!Math.Abs(r).Equals(r)) throw new ArithmeticException("The flag value has more than a single bit set."); + return Convert.ToByte(r); + } + /// Throws an exception if a flag value does not exist in a specified enumeration. /// The enumerated type. /// The value to check. /// Name of the argument to display in the exception. "value" is used if no value or null is supplied. /// - public static void CheckHasValue(T value, string argName = null) + public static void CheckHasValue(T value, string argName = null) where T : struct, System.Enum { - CheckIsEnum(); if (IsFlags()) { var allFlags = 0L; @@ -35,15 +50,15 @@ namespace Vanara.Extensions /// The enumerated value. /// The flags to clear or unset. /// The resulting enumerated value after the has been unset. - public static T ClearFlags(this T flags, T flag) where T : struct, IConvertible => flags.SetFlags(flag, false); + public static T ClearFlags(this T flags, T flag) where T : struct, System.Enum => flags.SetFlags(flag, false); /// Combines enumerated list of values into a single enumerated value. /// The enumerated type. /// The flags to combine. /// A single enumerated value. - public static T CombineFlags(this IEnumerable flags) where T : struct, IConvertible + public static T CombineFlags(this IEnumerable flags) where T : struct, System.Enum { - CheckIsEnum(true); + CheckHasFlags(); long lValue = 0; foreach (var flag in flags) { @@ -57,9 +72,8 @@ namespace Vanara.Extensions /// The enumerated type. /// The enumerated value. /// The description, or null if one is not set. - public static string GetDescription(this T value) where T : struct, IConvertible + public static string GetDescription(this T value) where T : struct, System.Enum { - CheckIsEnum(); // If this is flag, return flags if there are more than one. if (IsFlags() && value.GetFlags().Count() > 1) return value.ToString(CultureInfo.InvariantCulture); @@ -78,9 +92,9 @@ namespace Vanara.Extensions /// The enumerated type. /// The enumerated value. /// An enumeration of individual flags that compose the . - public static IEnumerable GetFlags(this T value) where T : struct, IConvertible + public static IEnumerable GetFlags(this T value) where T : struct, System.Enum { - CheckIsEnum(true); + CheckHasFlags(); foreach (T flag in Enum.GetValues(typeof(T))) { if (value.IsFlagSet(flag)) @@ -93,9 +107,9 @@ namespace Vanara.Extensions /// The enumerated flag value. /// The flag value to check. /// true if is flag set; otherwise, false. - public static bool IsFlagSet(this T flags, T flag) where T : struct, IConvertible + public static bool IsFlagSet(this T flags, T flag) where T : struct, System.Enum { - CheckIsEnum(true); + CheckHasFlags(); var flagValue = Convert.ToInt64(flag); return (Convert.ToInt64(flags) & flagValue) == flagValue; } @@ -104,9 +118,8 @@ namespace Vanara.Extensions /// The enumerated type. /// The enumerated value. /// true if the specified value is valid; otherwise, false. - public static bool IsValid(this T value) where T : struct, IConvertible + public static bool IsValid(this T value) where T : struct, System.Enum { - CheckIsEnum(); if (IsFlags()) { long mask = 0, lValue = Convert.ToInt64(value); @@ -122,9 +135,9 @@ namespace Vanara.Extensions /// A reference to an enumerated value. /// The flag to set or unset. /// if set to true sets the flag; otherwise the flag is unset. - public static void SetFlags(ref T flags, T flag, bool set = true) where T : struct, IConvertible + public static void SetFlags(ref T flags, T flag, bool set = true) where T : struct, System.Enum { - CheckIsEnum(true); + CheckHasFlags(); var flagsValue = Convert.ToInt64(flags); var flagValue = Convert.ToInt64(flag); if (set) @@ -140,7 +153,7 @@ namespace Vanara.Extensions /// The flag to set or unset. /// if set to true sets the flag; otherwise the flag is unset. /// The resulting enumerated value after the has been set or unset. - public static T SetFlags(this T flags, T flag, bool set = true) where T : struct, IConvertible + public static T SetFlags(this T flags, T flag, bool set = true) where T : struct, System.Enum { var ret = flags; SetFlags(ref ret, flag, set); @@ -153,18 +166,16 @@ namespace Vanara.Extensions /// if set to true the check with also assert that the enumeration has the set and will throw an exception if not. /// /// - private static void CheckIsEnum(bool checkHasFlags = false) + private static void CheckHasFlags() where T : struct, System.Enum { - if (!typeof(T).IsEnum) - throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum"); - if (checkHasFlags && !IsFlags()) + if (!IsFlags()) throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute"); } /// Determines whether this enumerations has the set. /// The enumerated type. /// true if this instance has the set; otherwise, false. - private static bool IsFlags() => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)); + private static bool IsFlags() where T : struct, System.Enum => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)); /*/// Returns an indication if the enumerated value is either defined or can be defined by a set of known flags. /// The enumerated type.