FlashPatcher/FlashPatcher/TaskService/Native/EnumUtil.cs

148 lines
4.8 KiB
C#

using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
namespace System
{
internal static class EnumUtil
{
public static void CheckIsEnum<T>(bool checkHasFlags = false)
{
if (!typeof(T).IsEnum)
throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum");
if (checkHasFlags && !IsFlags<T>())
throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute");
}
public static bool IsFlags<T>() => Attribute.IsDefined(typeof(T), typeof(FlagsAttribute));
public static void CheckHasValue<T>(T value, string argName = null)
{
CheckIsEnum<T>();
if (IsFlags<T>())
{
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<T>(this T flags) where T : struct, IConvertible
{
CheckIsEnum<T>(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<T>(this T flags, T flag) where T : struct, IConvertible
{
CheckIsEnum<T>(true);
var flagValue = Convert.ToInt64(flag);
return (Convert.ToInt64(flags) & flagValue) == flagValue;
}
public static bool IsValidFlagValue<T>(this T flags) where T : struct, IConvertible
{
CheckIsEnum<T>(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<T>(ref T flags, T flag, bool set = true) where T : struct, IConvertible
{
CheckIsEnum<T>(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<T>(this T flags, T flag, bool set = true) where T : struct, IConvertible
{
var ret = flags;
SetFlags<T>(ref ret, flag, set);
return ret;
}
public static T ClearFlags<T>(this T flags, T flag) where T : struct, IConvertible => flags.SetFlags(flag, false);
public static IEnumerable<T> GetFlags<T>(this T value) where T : struct, IConvertible
{
CheckIsEnum<T>(true);
foreach (T flag in Enum.GetValues(typeof(T)))
{
if (value.IsFlagSet(flag))
yield return flag;
}
}
public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct, IConvertible
{
CheckIsEnum<T>(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<T>(this T value) where T : struct, IConvertible
{
CheckIsEnum<T>();
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;
}
/// <summary>
/// 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 <paramref name="defaultVal"/>. If <paramref name="defaultVal"/> is undefined, it returns the first declared item in the enumerated type.
/// </summary>
/// <typeparam name="TEnum">The enumeration type to which to convert <paramref name="value"/>.</typeparam>
/// <param name="value">The string representation of the enumeration name or underlying value to convert.</param>
/// <param name="ignoreCase"><c>true</c> to ignore case; <c>false</c> to consider case.</param>
/// <param name="defaultVal">The default value.</param>
/// <returns>An object of type <typeparamref name="TEnum"/> whose value is represented by value.</returns>
public static TEnum TryParse<TEnum>(string value, bool ignoreCase = false, TEnum defaultVal = default(TEnum)) where TEnum : struct, IConvertible
{
CheckIsEnum<TEnum>();
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;
}
}
}