整合之前寫的字串轉列舉和位元(bit)操作,為了保持.NET命名風格的一致性,位元操作改稱為旗標(flag)操作

之前寫的字串轉列舉沒考慮到多旗標([Flags]Enum)的情況,也在此做更新

a0758a7f56ab8ca69575bc825dee247e.jpg

更新前的命名風格
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);
    }
}

創作者介紹
創作者 GNAySolution 的頭像
Yang

GNAySolution

Yang 發表在 痞客邦 留言(0) 人氣( 12 )