C# 多选项位运算的优化(周、星期常用)

本文是作日志写的,因此没有太多介绍细节。

今天在测试过程中找出了一个问题。
  建立日程时,可以选择该日程是每周的周几重复提醒,比如:每周二、四提醒。
  因为值的范围只有7天,所以可以使用二进制和与运算来实现多选。

原来的代码是这样写的

    public class CalendarModel
    {
        // some fields
        public WeekDayEnum WeekDay { get; set; }
        private List<DayOfWeek> dayOfWeeks;
        //获取 已选的周几的集合
        public List<DayOfWeek> DayOfWeeks
        {
            get
            {
                dayOfWeeks = new List<DayOfWeek>();
                // Bug, 就是这里 ToString得到的是数值,可能之前他扩展ToString 以取序列
                string[] tempWeekDays = WeekDay.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string day in tempWeekDays)
                {
                    switch (day.Trim())
                    {
                        case "MO":
                            dayOfWeeks.Add(DayOfWeek.Monday);
                            break;
                        case "TU":
                            dayOfWeeks.Add(DayOfWeek.Tuesday);
                            break;
                        case "WE":
                            dayOfWeeks.Add(DayOfWeek.Wednesday);
                            break;
                        case "TH":
                            dayOfWeeks.Add(DayOfWeek.Thursday);
                            break;
                        case "FR":
                            dayOfWeeks.Add(DayOfWeek.Friday);
                            break;
                        case "SA":
                            dayOfWeeks.Add(DayOfWeek.Saturday);
                            break;
                        case "SU":
                            dayOfWeeks.Add(DayOfWeek.Sunday);
                            break;
                        default:
                            dayOfWeeks.Add(DayOfWeek.Monday);
                            break;
                    }
                }
                return dayOfWeeks;
            }
        }
        // some methods
    }
    public enum WeekDayEnum
    {
        None = 0,        //无
        MO = 1,           //周一
        TU = 2,            //周二....
        WE = 4,
        TH = 8,
        FR = 16,
        SA = 32,
        SU = 64
    }

优化后的代码

    public class CalendarModel
    {
        // some fields

        public Weekday Weekday { get; set; }

        public List<DayOfWeek> DayOfWeeks
        {
            get
            {
                return Weekday.ToOptions().ToDayOfWeeks();
            }
        }

        // not some methods
    }

Weekday 不变.
其中ToOptions是 Weekday的扩展方法,在另一个文件中

public static class WeekdayExtensions
    {
        #region Utilities
        /// 转换..(暂未Public)
        private static DayOfWeek ToDayOfWeek(this Weekday e)
        {
            switch (e)
            {
                case Weekday.MO:
                    return DayOfWeek.Monday;
                case Weekday.TU:
                    return DayOfWeek.Tuesday;
                case Weekday.WE:
                    return DayOfWeek.Wednesday;
                case Weekday.TH:
                    return DayOfWeek.Thursday;
                case Weekday.FR:
                    return DayOfWeek.Friday;
                case Weekday.SA:
                    return DayOfWeek.Saturday;
                case Weekday.SU:
                    return DayOfWeek.Sunday;
                default:
                    return (DayOfWeek)(-1);
            }
        }
        #endregion

        #region  Weekday Convert To bit Array
        public static int[] ToIntArray(this Weekday[] e)
        {
            return Array.ConvertAll(e, x => (int)x);
        }
        #endregion

        #region Weekday bit options extensions
        /// 是否已选择指定项目
        public static bool HasOption(this Weekday e, params Weekday[] param)
        {
            return BitOptionExtensions.HasOption((int)e, param.ToIntArray());
        }

        /// 是否已选择指定项目
        /// (ToThink,受应用方式影响,暂不开放 int for bit option 的扩展)
        //public static bool HasOption(this int e, params Weekday[] param)
        //{
        //    return BitExtensions.HasOption(e, param.ToIntArray());
        //}

        /// 返回已选择的项
        //public static Weekday[] ToOptions(this Weekday e)
        public static Weekday[] ToOptions(this Weekday e)
        {
            var result = from Weekday t in Enum.GetValues(typeof(Weekday))  //or e.AllValues()
                         where (t & e) == t && (int)t != 0
                         select t;
            return result.ToArray();
        }

        /// 返回选择后的项目值
        public static int ToOptionId(this Weekday[] e)
        {
            return BitOptionExtensions.ToOptionId(e.ToIntArray());
        }
        #endregion
        /// 我是不太推荐,底层的方法返回List
        public static List<DayOfWeek> ToDayOfWeeks(this Weekday[] e)
        {
            return e.Select(ToDayOfWeek).Where(x=> (int)x != -1).ToList();
        }
    }

这里的 ToDayOfWeek 方法 是没有改变多少,是可以优化一下

注:在ToPotions中,增加了 (int)t != 0 这是因为 枚举里多了一个 None=0。
(在概念中本没有None)

WeekdayExtensions 内部使用了 BitExtensions

/// <summary>Bit运算选项扩展</summary>
    public static class BitOptionExtensions
    {
        /// 是否已选择指定项
        public static bool HasOption(this int e, params int[] param)
        {
            // 默认 就是 true, 这样会比默认false的时间复杂度小很多。
            var result = true;
            for (int i = 0; i < param.Length; i++)
            {
                var temp = param[i];
                if (result)
                    result = temp == (e & temp);
            }
            return result;
        }

        /// 返回已选择项集合
        /// (即以数组形式分离所有值)
        public static int[] ToOptions(this int e, int[] values)
        {
            var result = from t in values
                         where (t & e) == t
                         select t;

            return result.ToArray();
        }

        /// 返回选择后的项目值
        public static int ToOptionId(this int[] e)
        {
            var result = 0;
            for (int i = 0; i < e.Length; i++)
            {
                result = result | e[i];
            }
            return result;
        }

        /// 获得所有可选项
        public static TEnum[] AllValues<TEnum>(this TEnum e) where TEnum : struct
        {
            return (from TEnum a in Enum.GetValues(typeof(TEnum)) select a).ToArray();
        }
    }

上面BitExtensions是可以收留的,WeekdayExtensions是可以复制修改方便以后项目。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。