概述:C#枚举的常用使用。
一 什么是枚举?
枚举是一种值类型。枚举类型是包含一组已命名常量的独特值类型。
eg:某种情况下,我们需要标识某任务的处理状态,其状态包括 待处理,正在处理,已处理。
我们可以使用,0,1,2来标识 三个状态,但是我们可以定义为枚举,那样具有更好的可读性,避免硬编码。
public enum TaskState : int
{
WatieToDeal = 0,
Dealing = 1,
Dealed = 2,
}
二 如何定义枚举?
枚举使用一种整型值类型作为其基础存储(默认是int), 并提供离散值的语义含义。
public enum TaskState : int
{
WatieToDeal = 0,
Dealing = 1,
Dealed = 2,//
}
三 枚举的特点与注意事项?
1. 默认情况下,第一个枚举值0
(从技术上说,是0显示转型为基础枚举类型),后续每一项递增1(从技术上说,是0显示转型为基础枚举类型),后续每一项递增1,但是可以显示为枚举赋值。
public enum ConnectionState
{
Disconnected,//值为 0
Connecting = 10,
Connected,//值为 11
Joined = Connected,//值为 11(将Connected引用的值赋值给Joined)
Disconnecting//值为12
}
注释:
- 值 0 可以隐式转换为 枚举变量。特别注意值0应该设置为枚举。
-
如果创建的是值枚举而不是标志枚举,创建 None 枚举常量仍十分有用。
(原因是在默认情况下,公共语言运行库会将用于枚举的内存初始化为零。因此,如果不定义值为零的常量,则枚举在创建时将包含非法值。)- 如果明显存在应用程序需要表示的默认情况,请考虑使用值为零的枚举常量表示默认值。
- 如果不存在默认情况,请考虑使用值为零的枚举常量(这意味着该情况不由任何其他枚举常量表示)。
2. 枚举总有一个基础类型
基础类型包括 byte
、sbyte
、short
、ushort
、int
(默认)、uint
、long
或 ulong
,但是可以使用继承语法
来指定一个基础类型(注释,所以枚举的性能取决于基础类型的性能)
public eumn ConnectionState:short
{
//... ...
}
3. 未定义枚举值也能转换成功。
只要值能成功转型为基础类型,就会成功。
eg:完全可以将42转型为一个ConnectionState
,即使当前没有定义对应的ConnectionState
的枚举值。
ConnectionState state = (ConnectionState)42;
优点:在没有对应的枚举值得前提下也允许转型,优点在于枚举能在未来的API发布中添加新值,而且不会破坏早起版本。
缺点:开发者在编码时必须谨慎,要主动考虑到位命名值得可能性。
注释:
- 为枚举变量赋值的时候,尽量使用枚举名称赋值;
如果用值类型变量强制转换赋值,需要考虑值类型变量可能未在枚举中定义名称的情况。 - 在定义采用枚举常量作为值的方法或属性时,应考虑对该值进行验证。
原因是即使没有在枚举中定义某个数值,也可以将该数值强制转换为枚举类型。
4. 枚举与基础类型相互转换必须显示转换
从枚举转换成基础类型,以及从基础类型转换为枚举类型,都必须显示转换,而不是隐式转换。
//eg:
//基础类型转枚举
ConnectionState state01 = (ConnectionState)42;//正确
ConnectionState state02 = 42;//错误 编译报错
//枚举转基础类型
int int01=(int)enum02;
int int01=enum02;//错误 编译报错
//特殊的
ConnectionState enum03 = 0;
5. 枚举插入值会顺移
在一个枚举中部插入一个枚举值,会使其后的所有枚举值发生顺移。
//old
public eumn ConnectionState
{
Disconnected,//0
Connecting ,//1
}
//new
public eumn ConnectionState
{
Disconnected,//0
Connected,//1
Connecting ,//2 顺移了
}
虽然允许在代码未来的版本中为一个枚举添加额外的值,但是这样做时候要注意,原来的值可能会顺移。
避免发生这类情况,可以在枚举末尾插入新的枚举值,或者显示地进行赋值(常用)。
//较好的方法 01
public eumn ConnectionState
{
Disconnected,//0
Connecting ,//1
Connected,//2 插入到枚举末尾
}
//较好的方法 02
public eumn ConnectionState
{
Connected=2,//2 显示赋值后,不考虑 枚举间的位置
Disconnected=0,//0
Connecting=1 ,//1
}
四 枚举的优势
- 代码更容易维护
- 代码更清晰,可读性
- 枚举也较容易键入
五 字符串与枚举值转换
1. 枚举值转换为枚举值标识符
使用ToString()
方法。
enum ConnectionState : short
{
Disconnected,
Connecting = 10,
Connected,
Joined = Connected,
Disconnecting,
}
class Program
{
static void Main(string[] args)
{
ConnectionState enum01 = ConnectionState.Disconnected;
Console.WriteLine(enum01.ToString());
//打印 Disconnected
ConnectionState enum02 = (ConnectionState)44;
Console.WriteLine(enum02.ToString());
//打印 44
Console.WriteLine("键入任何键退出... ...");
Console.ReadKey();
}
}
2. 字符串转换为枚举
使用:Enum.Parse()
, Enum.TryParse()
, Enum.TryEnum<T>()
string str = "Joined";
//Enum.Parse() 要抛异常 需处理
ConnectionState enmu01 = (ConnectionState)Enum.Parse(typeof(ConnectionState), str);
Console.WriteLine(enmu01);//打印 Connected
//Enum.TryParse() 不抛异常
ConnectionState enum02;
bool success02 = Enum.TryParse<ConnectionState>(str, out enum02);
Console.WriteLine(enum02);//打印 Connected
Console.WriteLine(success02);//打印 true
六 Flag
属性
C#位域主要用于.Net里面对于某一个事物有多种混合状态时使用,如,权限管理,文件读写权限等等
- 对枚举使用
FlagsAttribute
自定义属性。 - 用 2 的幂(即 1、2、4、8 等)定义枚举常量。这意味着组合的枚举常量中的各个标志都不重叠。
- 对枚举(数值)执行按位运算(AND、OR、XOR),常用的有 | & ^ &~
具体含义:
|
表示两边求并集(元素相加,相同元素只出现一次)
&
表示两边是否其中一个是另外一个的子集,如果是返回子集,否则返回0(如果其中一个包含另外一个,返回被包含的,否则返回0)
^
表示从两者的并集中去除两者的交集(把两个的元素合并到一起,如果两个中有公共元素,要将这个公共元素从合并的结果中去除)
&~
A &~ B 表示:A集合中去掉A与B的交集部分。与^区别是,^去掉交集部分后,还会合并B中不是交集的部分。 - 优点:数据库也支持位操作
select 1|2 as '|' ,(1|2)&1 as '&',(1|2)^(2|4) as '^' ,(1|2)&~(2|4) as '&~'
--3,1,5, 1
//使用方法:以权限为列
[Flags]
enum MyPermission
{
None = 0,
Select = 0x1 << 0,
Download = 0x1 << 1,
Delete = 0x1 << 2,
Update = 0x1 << 3,//int 最大值可以写到30
User = Select | Download,//值为 1+2=3
Admin = Select | Download | Update,//值为 1+2+8=11
SystemAdmin = Admin | Delete,//值为 11+4=15
}
static void Main(string[] args)
{
/// | 表示两边求并集(元素相加,相同元素只出现一次)
///添加权限(列子含义)
// MyPermission.Select | MyPermission.Download | MyPermission.Delete
MyPermission permission01 = MyPermission.Select | MyPermission.Download | MyPermission.Delete | MyPermission.Select;
MyPermission permission02 = MyPermission.Select | MyPermission.Download | MyPermission.Select;//MyPermission.User
/// & 表示两边是否其中一个是另外一个的子集,如果是返回子集,否则返回0(如果其中一个包含另外一个,返回被包含的,否则返回0)
///拥有权限判断(列子含义)
MyPermission permission03 = MyPermission.User & MyPermission.Download;//MyPermission.Download
/// ^ 表示从两者的并集中去除两者的交集(把两个的元素合并到一起,如果两个中有公共元素,要将这个公共元素从合并的结果中去除)
/// 删除权限(列子含义)
MyPermission permission04 = MyPermission.User ^ MyPermission.Download;//MyPermission.Select
MyPermission permission05 = MyPermission.User ^ MyPermission.Download ^ MyPermission.Select;//0
//MyPermission permission06 = 0 ^ MyPermission.Select;//MyPermission.Select
/// ~ 表示取反,返回的结果我还不知道应该是什么,以后再查一下。用法主要和“&”一起使用,例如:去除其中的某个元素
/// A &~ B 表示:A集合中去掉A与B的交集部分。与^区别是,^去掉交集部分后,还会合并B中不是交集的部分。
MyPermission permission06 = MyPermission.User & ~MyPermission.Download;//MyPermission.Select
MyPermission permission07 = MyPermission.User & ~(MyPermission.Download | MyPermission.Update);//MyPermission.Select
MyPermission permission08 = MyPermission.User & ~(MyPermission.Download & MyPermission.Update);//MyPermission.User
///注释:对于0 这个值来说,我们把它考虑为空集合,空集合是任何集合的子集,空集合中一个元素都没有。
//空集合 不包含任何元素
MyPermission permission09 = MyPermission.User | MyPermission.None;//MyPermission.User
//空集合是任何集合的子集
MyPermission permission010 = MyPermission.User & MyPermission.None;//MyPermission.None
//空集合 不包含任何元素
MyPermission permission011 = MyPermission.User ^ MyPermission.None;//MyPermission.User
//空集合 不包含任何元素
MyPermission permission012 = MyPermission.User & ~MyPermission.None;//MyPermission.User
}
七 Descripttion
特性
在项目中通常用到的是在枚举变量上面加上Description。 枚举的值一般为int在数据库中占用空间比较小,枚举的变量用于给数据库中的字段赋值, 那么如果要显示字段就需要考虑到Descripttion特性,显示特定名称
[Flags]
public enum MyPermission
{
[Description("无任何权限")]
None = 0,
[Description("查询")]
Select = 0x1 << 0,
[Description("下载")]
Download = 0x1 << 1,
[Description("删除")]
Delete = 0x1 << 2,
[Description("更新")]
Update = 0x1 << 3,//int 最大值可以写到30
[Description("查询+下载")]
User = Select | Download,//值为 1+2=3
[Description("查询+下载+更新")]
Admin = Select | Download | Update,//值为 1+2+8=11
[Description("所有权限=查询+下载+更新+删除")]
SystemAdmin = Admin | Delete,//值为 11+4=15
}
public static class ExtensionMethods
{
public static string GetDescripetion<T>(this T value) where T : struct
{
string result = "";
try
{
if (value is Enum)
{
string str = value.ToString();
FieldInfo field = value.GetType().GetField(str);
object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (objs != null && objs.Length != 0)
{
DescriptionAttribute da = objs[0] as DescriptionAttribute;
if (string.IsNullOrWhiteSpace(da.Description))
{
}
}
}
}
catch { }
return result;
}
}