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);
}
}
}