J'ai écrit il y a quelque temps un ensemble de méthodes d'extension qui fonctionnent pour plusieurs types différents de Enums. Un en particulier fonctionne pour ce que vous essayez d'accomplir et gère les Enums avec les FlagsAttributeainsi que les Enums avec différents types sous-jacents.
public static tEnum SetFlags<tEnum>(this Enum e, tEnum flags, bool set, bool typeCheck = true) where tEnum : IComparable
{
if (typeCheck)
{
if (e.GetType() != flags.GetType())
throw new ArgumentException("Argument is not the same type as this instance.", "flags");
}
var flagsUnderlyingType = Enum.GetUnderlyingType(typeof(tEnum));
var firstNum = Convert.ToUInt32(e);
var secondNum = Convert.ToUInt32(flags);
if (set)
firstNum |= secondNum;
else
firstNum &= ~secondNum;
var newValue = (tEnum)Convert.ChangeType(firstNum, flagsUnderlyingType);
if (!typeCheck)
{
var values = Enum.GetValues(typeof(tEnum));
var lastValue = (tEnum)values.GetValue(values.Length - 1);
if (newValue.CompareTo(lastValue) > 0)
return lastValue;
}
return newValue;
}
De là, vous pouvez ajouter d'autres méthodes d'extension plus spécifiques.
public static tEnum AddFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
SetFlags(e, flags, true);
}
public static tEnum RemoveFlags<tEnum>(this Enum e, tEnum flags) where tEnum : IComparable
{
SetFlags(e, flags, false);
}
Celui-ci changera les types de Enums comme vous essayez de le faire.
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
return SetFlags(e, default(tEnum), true, false);
}
Soyez averti, cependant, que vous POUVEZ convertir entre n'importe lequel Enumet n'importe quel autre en Enumutilisant cette méthode, même ceux qui n'ont pas d'indicateur. Par exemple:
public enum Turtle
{
None = 0,
Pink,
Green,
Blue,
Black,
Yellow
}
[Flags]
public enum WriteAccess : short
{
None = 0,
Read = 1,
Write = 2,
ReadWrite = 3
}
static void Main(string[] args)
{
WriteAccess access = WriteAccess.ReadWrite;
Turtle turtle = access.ChangeType<Turtle>();
}
La variable turtleaura une valeur de Turtle.Blue.
Cependant, il y a sécurité à partir de Enumvaleurs non définies en utilisant cette méthode. Par exemple:
static void Main(string[] args)
{
Turtle turtle = Turtle.Yellow;
WriteAccess access = turtle.ChangeType<WriteAccess>();
}
Dans ce cas, accesssera défini sur WriteAccess.ReadWrite, car la WriteAccess Enumvaleur maximale de l est 3.
Un autre effet secondaire du mélange de Enums avec le FlagsAttributeet ceux qui n'en ont pas est que le processus de conversion n'entraînera pas une correspondance de 1 à 1 entre leurs valeurs.
public enum Letters
{
None = 0,
A,
B,
C,
D,
E,
F,
G,
H
}
[Flags]
public enum Flavors
{
None = 0,
Cherry = 1,
Grape = 2,
Orange = 4,
Peach = 8
}
static void Main(string[] args)
{
Flavors flavors = Flavors.Peach;
Letters letters = flavors.ChangeType<Letters>();
}
Dans ce cas, lettersaura une valeur de Letters.Hau lieu de Letters.D, puisque la valeur de support de Flavors.Peachest 8. De plus, une conversion de Flavors.Cherry | Flavors.Grapeen Lettersdonnerait Letters.C, ce qui peut sembler peu intuitif.