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ý Enum
các phần mềm FlagsAttribute
cũng như Enum
cá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 Enum
giố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ỳ Enum
và bất kỳ Enum
phươ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 turtle
sẽ có giá trị là Turtle.Blue
.
Tuy nhiên, có sự an toàn từ Enum
cá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, access
sẽ đượ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 Enum
s với FlagsAttribute
và 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, letters
sẽ có giá trị Letters.H
thay vì Letters.D
, vì giá trị hỗ trợ của Flavors.Peach
là 8. Ngoài ra, một chuyển đổi từ Flavors.Cherry | Flavors.Grape
thành Letters
sẽ mang lại lợi nhuận Letters.C
, điều này có vẻ không trực quan.