using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.ComponentModel; using Developpez.Dotnet.Collections; namespace Developpez.Dotnet { /// /// Fournit des méthodes d'extension pour manipuler les énumérations /// public static class EnumExtensions { /// /// Cette classe permet de mettre en cache les informations d'un type /// d'énumération en particulier. Les informations ne sont évaluées /// qu'une fois par type, dans le constructeur statique /// /// Le type d'énumération private static class EnumInfoCache where T : struct { private static readonly bool _hasFlags; private static readonly IEnumerable _values; private static readonly IDictionary _descriptions; static EnumInfoCache() { _hasFlags = Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)); _values = Enum.GetValues(typeof(T)).Cast(); _descriptions = _values.ToDictionary(v => v, v => GetDescription(v)).AsReadOnly(); } public static bool HasFlags { get { return _hasFlags; } } public static IEnumerable Values { get { return _values; } } public static IDictionary Descriptions { get { return _descriptions; } } private static string GetDescription(T value) { Type type = typeof(T); string name = Enum.GetName(type, value); if (name != null) { FieldInfo field = type.GetField(name); if (field != null) { DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute; if (attr != null) { return attr.Description; } } } return null; } } /// /// Vérifie que le type spécifié est une énumération, et optionnellement s'il a l'attribut 'Flags'. /// Si ce n'est pas le cas, une exception est levée. /// /// indique si le type à vérifier doit porter l'attribut Flags /// Le type à vérifier private static void CheckIsEnum(bool withFlags) where T : struct { if (!typeof(T).IsEnum) throw new ArgumentException(string.Format(ExceptionMessages.TypeIsNotEnum, typeof(T).FullName)); if (withFlags && !EnumInfoCache.HasFlags) throw new ArgumentException(string.Format(ExceptionMessages.TypeNotDecoratedWithFlags, typeof(T).FullName)); } /// /// Vérifie si le flag spécifié est présent dans la valeur /// /// Le type de l'énumération /// La combinaison de flags à vérifier /// Le flag à vérifier /// true si le flag est présent, false sinon public static bool HasFlag(this T value, T flag) where T : struct { CheckIsEnum(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flag); return (lValue & lFlag) != 0; } /// /// Convertit une combinaison de flags en une liste de valeurs de l'énumération /// /// Le type de l'énumération /// La combinaison de flags à convertir /// La liste des flags présents dans la combinaison public static IEnumerable GetFlags(this T value) where T : struct { CheckIsEnum(true); return value.GetFlagsIterator(); } private static IEnumerable GetFlagsIterator(this T value) where T : struct { foreach (T flag in EnumInfoCache.Values) { if (value.HasFlag(flag)) yield return flag; } } /// /// Définit la valeur d'un ou des flags dans une combinaison de flags /// /// Le type de l'énumération /// La combinaison de flags à modifier /// Le ou les flags à définir /// true pour ajouter le flag, false pour l'enlever /// La combinaison résultant de l'ajout ou de la suppression des flags public static T SetFlags(this T value, T flags, bool on) where T : struct { CheckIsEnum(true); long lValue = Convert.ToInt64(value); long lFlag = Convert.ToInt64(flags); if (on) { lValue |= lFlag; } else { lValue &= (~lFlag); } return (T)Enum.ToObject(typeof(T), lValue); } /// /// Ajoute un ou des flags à une combinaison /// /// Le type de l'énumération /// La combinaison de flags à modifier /// Le ou les flags à ajouter /// La combinaison résultant de l'ajout des flags public static T SetFlags(this T value, T flags) where T : struct { return value.SetFlags(flags, true); } /// /// Supprime un ou des flags d'une combinaison /// /// Le type de l'énumération /// La combinaison de flags à modifier /// Le ou les flags à supprimer /// La combinaison résultant de la suppression des flags public static T ClearFlags(this T value, T flags) where T : struct { return value.SetFlags(flags, false); } /// /// Convertit une liste de flags en une combinaison de ces flags /// /// Le type de l'énumération /// La liste de flags à combiner /// La combinaison des flags de la liste public static T CombineFlags(this IEnumerable flags) where T : struct { CheckIsEnum(true); long lValue = 0; foreach (T flag in flags) { long lFlag = Convert.ToInt64(flag); lValue |= lFlag; } return (T)Enum.ToObject(typeof(T), lValue); } /// /// Renvoie, si elle est définie, la description d'une valeur d'une énumération, spécifiée par /// l'attribut DescriptionAttribute. Si la description n'est pas définie, renvoie null. /// /// Le type de l'énumération /// la valeur pour laquelle obtenir une description /// La description de la valeur si elle est définie, null sinon. public static string GetDescription(this T value) where T : struct { return EnumInfoCache.Descriptions[value]; } /// /// Convertit une chaine en une valeur d'énumération, en ignorant éventuellement la casse /// /// Type d'énumération souhaité /// Chaine à convertir /// true pour ignorer la casse, false sinon /// La valeur d'énumération correspondant à la chaine public static T ToEnum(this string stringValue, bool ignoreCase) where T : struct { CheckIsEnum(false); return (T)Enum.Parse(typeof(T), stringValue, ignoreCase); } /// /// Convertit une chaine en une valeur d'énumération /// /// Type d'énumération souhaité /// Chaine à convertir /// La valeur d'énumération correspondant à la chaine public static T ToEnum(this string stringValue) where T : struct { return stringValue.ToEnum(false); } /// /// Convertit un entier signé sur 8 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this sbyte value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier signé sur 16 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this short value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier signé sur 32 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this int value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier signé sur 64 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this long value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier non signé sur 8 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this byte value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier non signé sur 16 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this ushort value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier non signé sur 32 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this uint value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } /// /// Convertit un entier non signé sur 64 bits en une valeur d'énumération /// /// Type d'énumération souhaité /// Valeur à convertir /// La valeur d'énumération correspondant à la valeur public static T ToEnum(this ulong value) where T : struct { CheckIsEnum(false); return (T)Enum.ToObject(typeof(T), value); } } }