目录
- 一、入门篇:枚举基础
-
- [1. 枚举类型的定义](#1. 枚举类型的定义)
- [2. 枚举类型的优点](#2. 枚举类型的优点)
- [3. 枚举的基本使用](#3. 枚举的基本使用)
-
- [3.1 枚举的类型转换](#3.1 枚举的类型转换)
- [3.2 遍历枚举成员](#3.2 遍历枚举成员)
- [3.3 判断枚举值是否有效](#3.3 判断枚举值是否有效)
- 3.4枚举的比较
- [4. 枚举的设计规范](#4. 枚举的设计规范)
- 二、深入底层篇:存储、值与继承限制
-
- [1. 枚举的存储与表示](#1. 枚举的存储与表示)
- [2. 枚举底层类型选择原则](#2. 枚举底层类型选择原则)
- [3. 枚举的继承与限制](#3. 枚举的继承与限制)
- 三、进阶使用篇
-
- [1. 标志 (Flags )枚举位运算](#1. 标志 (Flags )枚举位运算)
- [2. 枚举的泛型方法](#2. 枚举的泛型方法)
- [3. 枚举的自定义属性](#3. 枚举的自定义属性)
- [4. 枚举的扩展方法](#4. 枚举的扩展方法)
- 四、总结
- 参考文档
一、入门篇:枚举基础
1. 枚举类型的定义
枚举(Enumeration)由一组命名常量(称为枚举器)组成,用于建立一系列相互关联的整数常量,通过为这些常量分配描述性名称来增强代码的可读性和可管理性。
- 语法 :
enum 枚举名 { 成员名称 = 整数值, 其他成员名称, ... }
- 要点 :
- 枚举成员之间用","隔开。
- 枚举类型可以继承
byte
、sbyte
、short
、ushort
、int
、uint
、long
或ulong
类型。 - 第一个枚举成员如果没有显式设定值,则默认值为0,后续成员依次加1。
- 指定值 :也可以为枚举成员指定特定的值。
- 如果枚举的第一个成员没有显式赋值,则其默认值为0,后续成员依次递增。
- 如果后续某个成员显式赋值,则从这个成员开始,后续成员的值在其基础上依次递增。
c#
// 定义一个名为Weekday的枚举类型,继承自int类型
enum Weekday : int {
// 枚举成员之间用逗号隔开
Monday = 1, // 显式设定值为1
Tuesday, // 没有显式设定值,自动加1,值为2
Wednesday, // 自动加1,值为3
Thursday, // 自动加1,值为4
Friday, // 自动加1,值为5
Saturday, // 自动加1,值为6
Sunday // 自动加1,值为7
}
enum StatusCode { Success = 200, NotFound = 404, InternalServerError = 500 }
// 如果枚举的第一个成员没有显式赋值,则其默认值为0,后续成员依次递增
enum DefaultEnum1 { First, Second, Third }
// 如果后续某个成员显式赋值,则从这个成员开始,后续成员的值在其基础上依次递增
enum DefaultEnum2 { First, Second = 10, Third }
Console.WriteLine($"DefaultEnum1.First的值:{(int)DefaultEnum1.First}"); // 0
Console.WriteLine($"DefaultEnum1.Second的值:{(int)DefaultEnum1.Second}"); // 1
Console.WriteLine($"DefaultEnum1.Third的值:{(int)DefaultEnum1.Third}"); // 2
Console.WriteLine($"DefaultEnum2.First的值:{(int)DefaultEnum2.First}"); // 0
Console.WriteLine($"DefaultEnum2.Second的值:{(int)DefaultEnum2.Second}"); // 10
Console.WriteLine($"DefaultEnum2.Third的值:{(int)DefaultEnum2.Third}"); // 11
2. 枚举类型的优点
- 资源占用少:枚举是在栈中建立的数值类型,相比堆中建立的数据类型,运行程序时需要更少的处理器和内存资源,有助于提高程序的运行效率,降低系统资源的消耗。
- 性能高:枚举类型实质上是整数类型的别名,具有与整数相同的性能特征,这意味着在进行各种运算和操作时,枚举类型能够像整数一样快速高效地执行,不会因类型转换等因素而产生额外的性能开销。
- 代码可读性强:枚举类型为处理一组相关的常数提供了一种清晰的方式,通过为常数赋予具有明确意义的名称,使得代码更加直观易懂,其他开发者阅读代码时能够更快地理解代码的意图和逻辑,便于后续的代码维护和扩展。
- 类型安全:使用枚举类型可以确保在代码中处理的常数值是预定义好的枚举成员之一,避免了使用普通的整数常量时可能出现的错误赋值或传递非法值的情况,从而提高了代码的健壮性和可靠性,减少潜在的运行时错误。
3. 枚举的基本使用
3.1 枚举的类型转换
-
获取枚举成员的整数值 :
(int)枚举.成员
c#Weekday today = Weekday.Monday; int dayValue = (int)today; // dayValue的值是0 int value = 4; Weekday day = (Weekday)value; // day的值是Weekday.Thursday
-
字符串与枚举的相互转换 :
- 获取枚举成员的字符串值 :
枚举.成员.ToString()
或Enum.GetName(typeof(枚举名), 枚举值)
- 字符串转枚举:
Enum.Parse(typeof(枚举名), 字符串值)
或(枚举名)Enum.Parse(typeof(枚举名), 字符串值, true)
(忽略大小写)。
c#// 获取枚举成员的字符串值 Weekday day = Weekday.Friday; string dayName = day.ToString(); // 使用ToString()方法 Console.WriteLine("枚举成员的字符串值:" + dayName); string dayName2 = Enum.GetName(typeof(Weekday), day); // 使用Enum.GetName()方法 Console.WriteLine("枚举成员的字符串值:" + dayName2); // 忽略大小写字符串转枚举 string dayStringIgnoreCase = "saturday"; Weekday parsedDayIgnoreCase = (Weekday)Enum.Parse(typeof(Weekday), dayStringIgnoreCase, true); Console.WriteLine("忽略大小写字符串转枚举:" + parsedDayIgnoreCase);
- 获取枚举成员的字符串值 :
3.2 遍历枚举成员
使用 Enum.GetValues(typeof(枚举名))
获取枚举的所有成员。
c#
// 遍历枚举成员
Console.WriteLine("枚举的所有成员:");
foreach (Weekday weekday in Enum.GetValues(typeof(Weekday))) {
Console.WriteLine(weekday);
}
3.3 判断枚举值是否有效
使用 Enum.IsDefined(typeof(枚举名), 值)
。
c#
// 判断枚举值是否有效
int validValue = 5; // 对应Weekday.Friday
int invalidValue = 10; // 无效的枚举值
Console.WriteLine("枚举值" + validValue + "是否有效:" +
Enum.IsDefined(typeof(Weekday), validValue));
Console.WriteLine("枚举值" + invalidValue + "是否有效:" +
Enum.IsDefined(typeof(Weekday), invalidValue));
3.4枚举的比较
- 比较枚举值 :可以直接使用比较运算符(如
==
、!=
、<
、>
等)比较两个枚举值的大小,比较的是枚举成员的整数值。 - 比较枚举成员名称 :如果需要比较枚举成员的名称字符串,可以先将枚举值转换为字符串,然后使用字符串的比较方法(如
String.Equals
、String.Compare
等)进行比较。
c#
// 定义一个枚举
enum Sex { 男 = 1, 女 = 2 }
// 比较枚举值
Sex sex1 = Sex.男;
Sex sex2 = Sex.女;
Console.WriteLine(sex1 == sex2); // false
Console.WriteLine(sex1 != sex2); // true
Console.WriteLine(sex1 > sex2); // false
Console.WriteLine(sex1 < sex2); // true
// 比较枚举成员名称
string sex1Name = sex1.ToString();
string sex2Name = sex2.ToString();
Console.WriteLine(String.Equals(sex1Name, sex2Name)); // false
Console.WriteLine(String.Compare(sex1Name, sex2Name) == 0); // false
Console.WriteLine(String.Compare(sex1Name, sex2Name) < 0); // true
Console.WriteLine(String.Compare(sex1Name, sex2Name) > 0); // false
4. 枚举的设计规范
- 命名 :简单枚举的命名采用单数形式,不要使用
Enum
、Flag
、Flags
作为枚举类型的后缀。 - 零值枚举元素:考虑显式定义零值枚举元素,以防止未初始化的枚举值导致的意外行为。
- 返回空实例 :方法或属性返回枚举时,宁可返回一个空实例(如
Enum.GetValues(typeof(枚举名))[0]
)也不要返回空值(null
),以提高代码的健壮性。
二、深入底层篇:存储、值与继承限制
1. 枚举的存储与表示
- 枚举在底层是通过整数来存储的,每个枚举成员对应一个整数值。
- 枚举类型的变量在内存中占用的空间取决于其基础类型(如
int
、byte
等)。-
为什么要指定枚举值的底层类型
指定枚举值的底层类型的目的是为了节省内存空间,或者适应特定的数据源。不同的整数类型占用的内存空间和取值范围不同,如下表所示:
类型 内存空间 取值范围 byte 1 字节 0 到 255 sbyte 1 字节 -128 到 127 short 2 字节 -32768 到 32767 ushort 2 字节 0 到 65535 int 4 字节 -2147483648 到 2147483647 uint 4 字节 0 到 4294967295 long 8 字节 -9223372036854775808 到 9223372036854775807 ulong 8 字节 0 到 18446744073709551615
-
2. 枚举底层类型选择原则
-
根据成员数量和值大小选择:当枚举值的成员数量较少且数值较小时,应优先选用较小的整数类型作为底层类型,以节省内存空间并提升性能。
例如,若枚举值仅有四个成员,可选用
byte
作为底层类型,相较于使用int
,可节省 3 个字节的内存空间。 -
依据数据源特性选择:若枚举值需与特定数据源(如数据库、文件或网络)相适配,则应选用与数据源相同或兼容的整数类型作为底层类型,以避免类型转换带来的错误或额外开销。
例如,当数据源为 16 位无符号整数时,宜选用
ushort
作为底层类型,而非int
,这样可确保数据的一致性和准确性。
3. 枚举的继承与限制
- 枚举不能继承自除基本整数类型以外的其他类型。
- 枚举成员的值必须在其基础类型的范围内。
c#
using System;
using System.Runtime.InteropServices;
// 获取枚举类型的大小
int WeekdayenumSize = sizeof(Weekday);
Console.WriteLine("Weekday枚举类型占用的内存空间大小:" + WeekdayenumSize + " 字节");
// 定义一个继承自byte类型的枚举
enum Color : byte { Red, Green, Blue }
// 获取枚举类型的大小
int enumSize = sizeof(Color);
Console.WriteLine("枚举类型占用的内存空间大小:" + enumSize + " 字节");
// 获取byte类型的大小
int byteSize = sizeof(byte);
Console.WriteLine("byte类型占用的内存空间大小:" + byteSize + " 字节");
// 比较枚举类型和byte类型占用的内存空间大小
if (enumSize == byteSize) {
Console.WriteLine("继承自byte类型的枚举占用的内存空间与byte类型相同");
} else {
Console.WriteLine("继承自byte类型的枚举占用的内存空间与byte类型不同");
}
c#
Weekday枚举类型占用的内存空间大小:4 字节
枚举类型占用的内存空间大小:1 字节
byte类型占用的内存空间大小:1 字节
继承自byte类型的枚举占用的内存空间与byte类型相同
三、进阶使用篇
1. 标志 (Flags )枚举位运算
PS:可查看我的另一篇文章查看关于位运算更多内容。
位运算始末 |详解、特性思考、示例、运算巧思、相关算法、实际应用 (以C#为例)_c#归零-CSDN博客
- 定义 :通过给枚举加上
[Flags]
特性,使其能够表示多个枚举值的组合。 - 赋值:枚举成员的值通常定义为2的幂(如1, 2, 4, 8等),以便进行位运算。
- 使用 :
- 组合枚举值:使用位或运算符
|
。 - 检查是否包含某个枚举值:使用位与运算符
&
和比较运算符==
。 - 去除某个枚举值:使用位异或运算符
^
。
- 组合枚举值:使用位或运算符
c#
// 定义一个简单的枚举
public enum Sex { 女 = 0, 男 = 1 }
// 定义一个标志枚举
[Flags]
public enum Role {
未分配 = 0,
删除数据 = 1,
修改数据 = 2,
新增数据 = 4,
查看数据 = 8
}
// 获取枚举成员的字符串值和整数值
string sexString = Sex.男.ToString();
int sexValue = (int)Sex.男;
// 组合枚举值
Role userRole = Role.删除数据 | Role.修改数据;
// 检查是否包含某个枚举值
bool hasDeletePermission = (userRole & Role.删除数据) == Role.删除数据;
// 输出结果
Console.WriteLine($"Sex: {sexString}, Value: {sexValue}");
Console.WriteLine($"User Role: {userRole}, Has Delete Permission: {hasDeletePermission}");
c#
Sex: 男, Value: 1
User Role: 删除数据, 修改数据, Has Delete Permission: True
2. 枚举的泛型方法
可以编写泛型方法来处理不同类型的枚举。例如:
c#
public static T GetEnumValue<T>(int value) where T : struct, Enum
{
return (T)Enum.ToObject(typeof(T), value);
}
Weekday day = GetEnumValue<Weekday>(3); // day的值是Weekday.Wednesday
在这个例子中,GetEnumValue
方法接受一个整数值和一个枚举类型作为参数,返回对应的枚举值。通过泛型方法,可以处理不同类型的枚举,提高代码的复用性.
3. 枚举的自定义属性
可以为枚举成员添加自定义属性,以存储额外的信息。这可以通过扩展方法来实现。
可以为枚举成员添加属性,以便存储额外的信息。例如:
c#
enum ErrorCode
{
[Description("无效输入")]
InvalidInput,
[Description("超时")]
Timeout,
[Description("连接失败")]
ConnectionFailed
}
在这个例子中,为ErrorCode
枚举的每个成员添加了Description
属性,用于存储错误代码的描述信息。可以通过反射来获取这些属性的值,例如:
c#
ErrorCode error = ErrorCode.InvalidInput;
var description = typeof(ErrorCode)
.GetField(error.ToString())
.GetCustomAttribute<DescriptionAttribute>()
?.Description;
Console.WriteLine(description); // 输出: 无效输入
4. 枚举的扩展方法
可以为枚举类型定义扩展方法,以便扩展枚举的功能。例如:
c#
public static class WeekdayExtensions
{
public static bool IsWeekend(this Weekday day)
{
return day == Weekday.Saturday || day == Weekday.Sunday;
}
}
Weekday today = Weekday.Saturday;
bool isWeekend = today.IsWeekend(); // true
在这个例子中,为Weekday
枚举定义了一个扩展方法IsWeekend
,用于判断一个工作日是否是周末.
四、总结
- 枚举基础
- 枚举定义:一种数据类型,定义一组命名常量,提升代码可读性和可维护性。
- 语法要点:
enum 枚举名 { 成员名称 = 整数值, 其他成员名称, ... }
,成员间逗号隔开,可继承多种整数类型。 - 枚举优点:在栈中建立,占用资源少;增强代码可读性和可维护性。
- 基本使用:包括类型转换(获取整数值、字符串值,字符串转枚举)、遍历成员(
Enum.GetValues(typeof(枚举名))
)、判断有效性(Enum.IsDefined(typeof(枚举名), 值)
)。 - 设计规范:命名单数形式;定义零值枚举元素;返回空实例非空值。
- 枚举的存储、值与继承限制
- 存储表示:底层整数存储,变量占用空间依基础类型定。指定底层类型可节省内存或适配数据源。
- 继承限制:不能继承除基本整数类型外的其他类型,成员值须在基础类型范围内。
- 枚举的进阶使用
- 比较:可直接比较枚举值大小,也可比较成员名称字符串。
- 标志枚举与位运算:
[Flags]
特性定义,成员值为2的幂,可组合、检查和去除枚举值。 - 泛型方法:编写泛型方法处理不同类型枚举,提高代码复用性。
- 自定义属性:为成员添加属性存储额外信息,可通过反射获取。
- 扩展方法:定义扩展方法扩展枚举功能,如判断工作日是否为周末。