C#温故知新(3)---毫不起眼的Enum

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wucdsg/article/details/79127190

1.引言

本篇总结来自于一个小小的开发需求,即给枚举一个中文名称,一般来说不推荐(或者有更加严格的说法是不予许)在代码中使用中文,那么有时候需要在界面上展示中文,怎么弄?贴标签,反射获取即可,网上的代码一堆哦(下面也会给出)。从这个不定点的开发需求出发,我将这个毫不起眼的Enum进行了总结,本篇不在传道解惑,意在温故知新,方便日后翻阅,若文中有瑕疵纰漏之处,请留言当面指正,不必留情。

2.熟悉的陌生人Enum

    public enum Week
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }

就这么用了,没什么特殊需求啊

  • 需要多个值怎么办,比如说一个用户有多个角色?
  • 为什么有的dll里的枚举值赋值:0,1,2,4,8,16…2^n,不是有默认值吗?吃多了撑得?
  • 枚举类型上面价格[Flags]什么鬼?查一下,位操作,记着就好了?什么是位操作,怎么个操作法儿啊?
  • 需要中文怎么办?switch…case一下,挨个判断一下,简单粗暴哦!

(1)问题1:关于枚举的默认值

  • 枚举是值类型(标准类型byte、sbyte、short、ushort、int、uint、long 或 ulong),每一个枚举型有默认值,如果不特殊设置默认值,则依次0,1,2,3,4,5…
    这里写图片描述
  • 如果仅仅设置其中一个枚举值,则该枚举值后面的值依次+1,前面的会不变,这样会造成问题的,下面的Demo可以说明,因此要避免出现这样的用法,说实话,我也没有见过这样用的,一般要么全部默认值,要么全部自定义,不会说只设置枚举项其中一个的值的。
    public enum Week
    {
        Monday,
        Tuesday=0,//默认值
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }
        Week week_today = Week.Monday;
        Console.WriteLine(week_today == 0);
        Console.WriteLine(week_today);
        Console.WriteLine((Week)2);
        Console.ReadKey();

这里写图片描述
(2)问题2:枚举的位操作[FlagsAttribute]

    [Flags]
    public enum Week
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }

给枚举贴上一个[Flags]特性标签,那么枚举变量可以进行位操作,一般用来取多个值,看看下面的两个Demo:

    //周末
    Week weekend = Week.Saturday | Week.Sunday;
    Console.WriteLine(weekend);

    //健身
    Week workout = Week.Monday | Week.Tuesday;
    Console.WriteLine(workout);
    Console.ReadKey();

这里写图片描述

操,什么情况?周末weekend输出的是两天,但是这两天不对啊,workout干脆就是一天了,Monday哪儿去了啊?带着这些问题查了一下[Flags]的位操作,原来是这样啊!

符号 描述 运算规则
& 1与1等于1,1与0等于0,0与0等于0
| 1或1等于1,1或0等于1,0或0等于0
^ 异或 相同得0,相异得1
~ 取反 如果某一位等于0,就将其转变为1;如果某一位等于1,就将其转变为0
<< 左移 位左移运算将整个数按位左移若干位,左移后空出的部分0
>> 右移 位右移运算将整个数按位右移若干位,右移后空出的部分填0

说明:默认情况下上面的枚举值依次为0,1,2,3,4,5,6,不妨先看看Week.Monday | Week.Tuesday,转为二进制(仅仅列出四位)即是0000|0001=0001,所以结果显示1所对应的Tuesday,而Week.Saturday | Week.Sunday,即是0101|0110=0111(7),将这个复合值分解的时候,分解成了Tuesday(1)和Sunday(6),这里为什么这样分解?而不是分解成3和4或者2和5,我并没有搞懂,有知道的大神可以留言回复。那么怎么解决存在复合值的问题呢?MSDN:在 2 的幂,即 1、 2、 4、 8 等中定义枚举常量。 这意味着不重叠中组合的枚举常量的各个标志。因此你常见的一些写法就出来了:

    /*直接二进制,简单易理解*/
    [Flags]
    public enum Week
    {
        Monday = 1,
        Tuesday = 2,
        Wednesday = 4,
        Thursday = 8,
        Friday = 16,
        Saturday = 32,
        Sunday = 64
    }
    /*左移操作的结果是一样的,00000001把1的值一直往左移动*/
    [Flags]
    public enum Week
    {
        Monday = 1,
        Tuesday = 1<<1,
        Wednesday = 1<<2,
        Thursday = 1<<3,
        Friday = 1<<4,
        Saturday = 1<<5,
        Sunday = 1<<6
    }
    /*16进制表示*/
    [Flags]
    public enum Week
    {
        Monday = 0x01,
        Tuesday = 0x02,
        Wednesday = 0x04,
        Thursday = 0x08,
        Friday = 0x10,
        Saturday = 0x20,
        Sunday = 0x40
    }

上述的三种表示方法均可,我进本上采用的是直接用整型表示,这里有一点需要注意的是2n(n>=0),上面的示例已经说明了0|1=1,因此不要把0包含进来,我看到网上的很多示例中都有包含0,这实际上是不对的。关于位复合枚举的操作,常用的还有如下操作:判断存在,剔除,添加,看看Demo(具体的位操作就不解释了,有兴趣的可以深入了解)

Week weekday = Week.Monday | Week.Tuesday | Week.Wednesday | Week.Thursday | Week.Friday;

Console.WriteLine("原始:"+weekday);
//判断是否包含枚举值
bool isContains = (weekday & Week.Friday) == Week.Friday;
//剔除枚举值
if (isContains)
   weekday = weekday & ~Week.Friday;
Console.WriteLine("剔除之后:" + weekday);
//添加枚举值
weekday = weekday | Week.Friday;
Console.WriteLine("添加之后:" + weekday);
Console.ReadKey();

这里写图片描述

(3)问题3:关于枚举的中文描述

    [Flags]
    public enum Week
    {
        [Description("星期一")]
        Monday = 1,
        [Description("星期二")]
        Tuesday = 2,
        [Description("星期三")]
        Wednesday = 4,
        [Description("星期四")]
        Thursday = 8,
        [Description("星期五")]
        Friday = 16,
        [Description("星期六")]
        Saturday = 32,
        [Description("星期日")]
        Sunday = 64
    }

主要是为了方便在使用的时候,尤其是在UI界面上展示时需要用到中文,看看下面的Demo:

    public static class EnumHelper
    {
        /// <summary>
        /// 反射获取Description
        /// </summary>
        /// <param name="enumName"></param>
        /// <returns></returns>
        public static string GetDescription(this Enum enumName)
        {
            string description = string.Empty;
            FieldInfo fieldInfo = enumName.GetType().GetField(enumName.ToString());
            if (fieldInfo == null) return enumName.ToString();
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attributes != null && attributes.Length > 0)
                description = attributes[0].Description;
            else
                description = enumName.ToString();
            return description;
        }

        /// <summary>
        /// Description转Enum
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="description"></param>
        /// <returns></returns>
        public static T GetEnumByDescription<T>(string description)
        {
            Type type = typeof(T);
            if (!type.IsEnum) throw new Exception("当前不是枚举类型!");
            DescriptionAttribute[] attributes = null;
            foreach (FieldInfo fieldInfo in type.GetFields())
            {
                if (fieldInfo == null) continue;
                attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (attributes != null && attributes.Length > 0)
                {
                    if (attributes[0].Description == description)
                        return (T)fieldInfo.GetValue(null);
                }
                else
                {
                    if (fieldInfo.Name == description)
                        return (T)fieldInfo.GetValue(null);
                }
            }
            throw new ArgumentException("未能找到对应的枚举值:" + description);
        }

        /// <summary>
        /// 获取枚举集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Dictionary<Enum,string> EnumToArrayList<T>(this Type type)
        {
            if (type.IsEnum)
            {
                Dictionary<Enum, string> result = new Dictionary<Enum, string>();
                Array _enumValues = Enum.GetValues(type);
                foreach (Enum value in _enumValues)
                {
                    result.Add(value, GetDescription(value));
                }
                return result;
            }
            return null;
        }
    }
            /*测试代码*/
            Week week_today = Week.Monday;
            Console.WriteLine(week_today.GetDescription());

            Week week_test = EnumHelper.GetEnumByDescription<Week>("星期五");
            Console.WriteLine(week_test);

            Dictionary<Enum, string> result = typeof(Week).EnumToArrayList<Week>();
            Console.WriteLine(result[Week.Thursday]);

这里写图片描述

3.参考文章

猜你喜欢

转载自blog.csdn.net/wucdsg/article/details/79127190