整合之前寫的字串轉列舉和位元(bit)操作,為了保持.NET命名風格的一致性,位元操作改稱為旗標(flag)操作
之前寫的字串轉列舉沒考慮到多旗標([Flags]Enum)的情況,也在此做更新

更新前的命名風格
BitOperator
CheckBit,檢查指定的位元其值是否不為0
GetBit,取出指定的位元值,屏蔽其他位元值
AddBit,指定的位元其值設定為1
RemoveBit,指定的位元其值設定為0
更新後的命名風格
FlagOperator
HasFlag,檢查指定位置的旗標是否存在(其值是否不為0)
GetFlag,取出指定位置的旗標(存在為1,不存在為0)
SetFlag,設定旗標,指定位置的旗標值設定為1
RemoveFlag,移除旗標,指定位置的旗標值設定為0
單元測試:
$"{ProcessPriorityClass.AboveNormal}|{FlagOperator.ConvertTo<ProcessPriorityClass>(ProcessPriorityClass.AboveNormal.ToString())}|{FlagOperator.ConvertTo<ProcessPriorityClass>(((int)ProcessPriorityClass.AboveNormal).ToString())}"
$"{ProcessPriorityClass.BelowNormal}|{FlagOperator.ConvertTo<ProcessPriorityClass>(ProcessPriorityClass.BelowNormal.ToString())}|{FlagOperator.ConvertTo<ProcessPriorityClass>(((int)ProcessPriorityClass.BelowNormal).ToString())}"
$"{FlagOperator.ConvertTo<DayOfWeek>("Sunday")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("monday")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("Tue")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("Wed.")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("tHURSDAY")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("f")}"
$"{FlagOperator.ConvertTo<DayOfWeek>("6")}"
//多旗標列舉([Flags]Enum)測試,以常見的FileShare做測試
$"{FlagOperator.ConvertTo<FileShare>(((int)FileShare.Read).ToString())}"
$"{FlagOperator.ConvertTo<FileShare>(((int)FileShare.Write).ToString())}"
$"{FlagOperator.ConvertTo<FileShare>(((int)(FileShare.Read | FileShare.Write)).ToString())}"
$"{FlagOperator.ConvertTo<FileShare>(((int)(FileShare.Read | FileShare.Write | FileShare.Delete)).ToString())}"
AboveNormal|AboveNormal|AboveNormal
BelowNormal|BelowNormal|BelowNormal
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
//多旗標列舉([Flags]Enum)測試正常
Read
Write
ReadWrite
ReadWrite, Delete
單元測試正常
另外要注意的是,.NET的列舉(Enum)預設是繼承int,列舉值可以設定成負數,但是旗標操作一般會把資料當成無符號數(unsigned),也就是大於等於0的正數(常見byte與uint)
設計列舉時,如果同時需要定義負數和旗標([Flags]Enum)操作,實務上我沒遇過這種情況,因此沒做測試,不確定會不會出問題
原始碼:
public class FlagOperator
{
public static readonly uint[] FlagValue = {
(uint)Math.Pow(2, 0),
(uint)Math.Pow(2, 1),
(uint)Math.Pow(2, 2),
(uint)Math.Pow(2, 3),
(uint)Math.Pow(2, 4),
(uint)Math.Pow(2, 5),
(uint)Math.Pow(2, 6),
(uint)Math.Pow(2, 7),
(uint)Math.Pow(2, 8),
(uint)Math.Pow(2, 9),
(uint)Math.Pow(2, 10),
(uint)Math.Pow(2, 11),
(uint)Math.Pow(2, 12),
(uint)Math.Pow(2, 13),
(uint)Math.Pow(2, 14),
(uint)Math.Pow(2, 15),
(uint)Math.Pow(2, 16),
(uint)Math.Pow(2, 17),
(uint)Math.Pow(2, 18),
(uint)Math.Pow(2, 19),
(uint)Math.Pow(2, 20),
(uint)Math.Pow(2, 21),
(uint)Math.Pow(2, 22),
(uint)Math.Pow(2, 23),
(uint)Math.Pow(2, 24),
(uint)Math.Pow(2, 25),
(uint)Math.Pow(2, 26),
(uint)Math.Pow(2, 27),
(uint)Math.Pow(2, 28),
(uint)Math.Pow(2, 29),
(uint)Math.Pow(2, 30),
(uint)Math.Pow(2, 31),
};
//將字串轉為指定的列舉型態,不分英文大小寫,支援英文或數字,支援帶點結尾或不帶點的英文縮寫,數字支援多旗標列舉([Flags]Enum)
public static Enum ConvertToEnum(in string source, in Type enumType)
{
string trim = source.Trim(' ', '.').ToLower();
foreach (Enum value in Enum.GetValues(enumType))
{
if (value.ToString().ToLower().StartsWith(trim) || trim == ((int)(object)value).ToString())
{
return value;
}
}
return (Enum)Enum.Parse(enumType, trim);
}
//將字串轉為指定的列舉型態,不分英文大小寫,支援英文或數字,支援帶點結尾或不帶點的英文縮寫,數字支援多旗標列舉([Flags]Enum)
public static T ConvertTo<T>(in string source) where T : Enum
{
return (T)ConvertToEnum(source, typeof(T));
}
public static bool HasFlag(in byte value, in int position)
{
if (position < 0 || position >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return (value & FlagValue[position]) > 0;
}
public static bool HaveFlags(in byte value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return (value & flags) == flags;
}
public static byte GetFlag(in byte value, in int position)
{
if (position < 0 || position >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return (byte)(value & FlagValue[position]);
}
public static byte GetFlags(in byte value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return (byte)(value & flags);
}
public static byte SetFlag(in byte value, in int position)
{
if (position < 0 || position >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return (byte)(value | FlagValue[position]);
}
public static byte SetFlags(in byte value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return (byte)(value | flags);
}
public static byte RemoveFlag(in byte value, in int position)
{
if (position < 0 || position >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
//return HasFlag(value, position) ? (byte)(value - FlagValue[position]) : value;
return (byte)(value & ~FlagValue[position]);
}
public static byte RemoveFlags(in byte value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(byte) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return (byte)(value & ~flags);
}
public static bool HasFlag(in uint value, in int position)
{
if (position < 0 || position >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return (value & FlagValue[position]) > 0;
}
public static bool HaveFlags(in uint value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return (value & flags) == flags;
}
public static uint GetFlag(in uint value, in int position)
{
if (position < 0 || position >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return value & FlagValue[position];
}
public static uint GetFlags(in uint value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return value & flags;
}
public static uint SetFlag(in uint value, in int position)
{
if (position < 0 || position >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
return value | FlagValue[position];
}
public static uint SetFlags(in uint value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return value | flags;
}
public static uint RemoveFlag(in uint value, in int position)
{
if (position < 0 || position >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(position)}={position}");
}
//return HasFlag(value, position) ? value - FlagValue[position] : value;
return value & ~FlagValue[position];
}
public static uint RemoveFlags(in uint value, params int[] positions)
{
if (positions == null || positions.Length <= 0)
{
throw new ArgumentException($"{nameof(positions)} == null || {nameof(positions)}.Length <= 0");
}
uint flags = 0;
foreach (int pos in positions)
{
if (pos < 0 || pos >= sizeof(uint) * 8)
{
throw new IndexOutOfRangeException($"{nameof(pos)}={pos}");
}
flags |= FlagValue[pos];
}
return value & ~flags;
}
public static byte Reverse(byte value)
{
value = (byte)(((value & 0xaa) >> 1) | ((value & 0x55) << 1));
value = (byte)(((value & 0xcc) >> 2) | ((value & 0x33) << 2));
return (byte)((value >> 4) | (value << 4));
}
public static uint Reverse(uint value)
{
value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1);
value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2);
value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4);
value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8);
return (value >> 16) | (value << 16);
}
}
請先 登入 以發表留言。