Escribí un conjunto de métodos de extensión un tiempo atrás que funcionan para varios tipos diferentes de Enum
s. Uno en particular funciona para lo que está tratando de lograr y maneja Enum
s con FlagsAttribute
y Enum
s con diferentes tipos subyacentes.
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;
}
Desde allí puede agregar otros métodos de extensión más específicos.
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);
}
Ésta cambiará tipos de Enum
s como si estuviera tratando de hacer.
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
return SetFlags(e, default(tEnum), true, false);
}
Se advirtió, sin embargo, que se puede convertir entre cualquier Enum
Enum
y cualquier otro uso de este método, incluso aquellos que no tienen banderas. Por ejemplo:
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 turtle
tendrá un valor de Turtle.Blue
.
Sin embargo, existe la seguridad de los valores Enum
indefinidos utilizando este método. Por ejemplo:
static void Main(string[] args)
{
Turtle turtle = Turtle.Yellow;
WriteAccess access = turtle.ChangeType<WriteAccess>();
}
En este caso, access
se establecerá en WriteAccess.ReadWrite
, ya que el WriteAccess
Enum
tiene un valor máximo de 3.
Otro efecto secundario de la mezcla de Enum
s con el FlagsAttribute
y los que no lo es que el proceso de conversión no dará como resultado una coincidencia de 1 a 1 entre sus valores.
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>();
}
En este caso, letters
tendrá un valor de Letters.H
en lugar de Letters.D
, ya que el valor de soporte de Flavors.Peach
es de 8. También, una conversión de Flavors.Cherry | Flavors.Grape
a Letters
produciría Letters.C
, que puede parecer poco intuitivo.
¿A qué desea convertir "desconocido"? –
Puede encasillar la enumeración en otros tipos de enumeración cuando ambos tienen los mismos valores, véase http://ideone.com/7lgvgf –