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是可以复制修改方便以后项目。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351