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]);