Tôi đã viết một tập hợp các phương thức mở rộng cách đây một thời gian hoạt động cho một số loại khác nhau Enum. Một công cụ cụ thể hoạt động cho những gì bạn đang cố gắng hoàn thành và xử lý Enumcác phần mềm FlagsAttributecũng như Enumcác phần tử cơ bản khác nhau.
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;
}
Từ đó bạn có thể thêm các phương pháp mở rộng khác cụ thể hơn.
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);
}
Điều này sẽ thay đổi các kiểu Enumgiống như bạn đang cố gắng làm.
public static tEnum ChangeType<tEnum>(this Enum e) where tEnum : IComparable
{
return SetFlags(e, default(tEnum), true, false);
}
Tuy nhiên, hãy cảnh báo rằng bạn CÓ THỂ chuyển đổi giữa bất kỳ Enumvà bất kỳ Enumphương pháp nào khác bằng phương pháp này, ngay cả những phương pháp không có cờ. Ví dụ:
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>();
}
Biến turtlesẽ có giá trị là Turtle.Blue.
Tuy nhiên, có sự an toàn từ Enumcác giá trị không xác định bằng cách sử dụng phương pháp này. Ví dụ:
static void Main(string[] args)
{
Turtle turtle = Turtle.Yellow;
WriteAccess access = turtle.ChangeType<WriteAccess>();
}
Trong trường hợp này, accesssẽ được đặt thành WriteAccess.ReadWrite, vìWriteAccess Enum có giá trị lớn nhất là 3.
Một tác dụng phụ khác của việc trộn Enums với FlagsAttributevà những không có nó là quá trình chuyển đổi sẽ không dẫn đến kết quả khớp 1-1 giữa các giá trị của chúng.
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>();
}
Trong trường hợp này, letterssẽ có giá trị Letters.Hthay vì Letters.D, vì giá trị hỗ trợ của Flavors.Peachlà 8. Ngoài ra, một chuyển đổi từ Flavors.Cherry | Flavors.Grapethành Letterssẽ mang lại lợi nhuận Letters.C, điều này có vẻ không trực quan.