1. 入门
写代码的时候,经常要用到一堆提前就知道的、有限的选项。比如:星期几、红绿灯的颜色、游戏难度等级、订单状态。这些选项通常都是固定的值。说到这就要聊聊今天的主角——枚举(enum)。
枚举就是一种特殊的数据类型,让你能声明一组有名字的常量。
enum就像一个分好格子的盒子,每个格子贴着独一无二的标签,标签和数字一一对应。
- 你的代码会变得更好读,而且自带注释;
- 不用再写那些神秘的“魔法数字”比如0、1、2,直接用有意义的名字:DayOfWeek.Monday 或 TrafficLight.Red;
- 如果你赋值错了,编译器会直接报错;
- 其实每个枚举成员背后……就是个普通的整数!(后面还会讲到)
2. 枚举的声明语法
来,咱们先写个第一个枚举——天气类型,以后做天气App能用上。代码长这样:
// 天气条件的枚举
public enum WeatherCondition
{
Sunny, // 0
Cloudy, // 1
Rainy, // 2
Stormy, // 3
Snowy // 4
}
- 关键字enum就是声明新类型。
- 大括号里写的是选项的名字。默认每个选项对应一个整数,从0开始(Sunny == 0,Cloudy == 1,以此类推)。
- 你也可以手动指定值:
public enum WeatherCondition
{
Sunny = 1,
Cloudy = 2,
Rainy = 4,
Stormy = 8,
Snowy = 16
}
如果你要让这些值和外部标准或者协议对上号,这样写就很方便。
3. 枚举的用法
假设你写了个小App——控制台程序,根据天气做点反应。
// 应用程序类
class Program
{
static void Main()
{
// 用我们的枚举存天气状态
WeatherCondition todayWeather = WeatherCondition.Sunny;
// 打印出来
Console.WriteLine($"今天的天气:{todayWeather} ({(int)todayWeather})");
// 模拟天气变化
todayWeather = WeatherCondition.Rainy;
Console.WriteLine($"哎呀!天气变了:{todayWeather} ({(int)todayWeather})");
}
}
会发生啥?
今天的天气:Sunny (0)
哎呀!天气变了:Rainy (2)
- todayWeather不是字符串,也不是数字,而是枚举的一个成员。
- 强制转成(int)可以看到它背后的“数字代码”。
顺便说一句,枚举和条件判断配合得贼好:
if (todayWeather == WeatherCondition.Rainy)
Console.WriteLine("带把伞吧!");
4. enum的实际用法场景
枚举都用在哪?
- 业务系统:订单状态(New、Processing、Shipped、Cancelled)。
- 用户管理系统:权限等级(User、Moderator、Admin)。
- 游戏:角色状态(Idle、Moving、Jumping、Falling)。
- GUI:按钮、消息、图标颜色啥的。
如果你深入.NET,会发现标准库里一大半类都用枚举!比如文件操作就有枚举来指定打开模式(读、写、创建)。
5. 显式赋值和取值范围
有时候你想把代码里用到的一组int值变成enum,其实很简单:
public enum CompassDirection
{
North = 10,
East = 20,
South = 30,
West = 40
}
现在CompassDirection.North = 10,East = 20,以此类推。如果有成员没写值,它会自动比前一个大1。
存储类型
默认enum用int(4字节整数)存。但你想省内存也可以指定底层类型:
public enum TinyEnum : byte
{
First, // 0
Second, // 1
Third // 2
}
这样每个枚举值只占一个字节!
可选类型有:byte、sbyte、short、ushort、int、uint、long、ulong。
6. enum和数字/字符串的转换
枚举 enum ↔ int 的转换:
要把enum转成int或者反过来,直接强制类型转换就行:
WeatherCondition current = WeatherCondition.Cloudy;
int number = (int)current; // 得到1
WeatherCondition fromNumber = (WeatherCondition)2; // 得到Rainy
枚举 enum ↔ string 的转换:
把enum转成字符串很简单:直接用ToString()方法。
// 枚举转字符串
string name = WeatherCondition.Stormy.ToString(); // "Stormy"
// 字符串转枚举用Enum.Parse
WeatherCondition parsed = (WeatherCondition)Enum.Parse(typeof(WeatherCondition), "Stormy");
// 也可以用Enum.TryParse
WeatherCondition parsedOk;
if (Enum.TryParse("Snowy", out parsedOk))
{
Console.WriteLine(parsedOk); // Snowy
}
常见错误:
如果你把一个数字强转成enum,但这个数字没对应的成员,编译器不会报错,但你会得到一个“虚拟”状态。
比如:
WeatherCondition weird = (WeatherCondition)999;
Console.WriteLine(weird); // 999(不会变成"Unknown"!)
所以,写这种转换的时候要小心点。
7. switch和enum天生一对
枚举(enum)和switch配合起来超爽。这样你可以很直观地“对不同枚举值做不同反应”,不用一堆if-else。
例子:根据天气做反应
public enum WeatherCondition
{
Sunny,
Cloudy,
Rainy,
Stormy,
Snowy
}
WeatherCondition today = WeatherCondition.Rainy;
switch (today)
{
case WeatherCondition.Sunny:
Console.WriteLine("晴天!可以出去玩。");
break;
case WeatherCondition.Cloudy:
Console.WriteLine("阴天。可以带件外套。");
break;
case WeatherCondition.Rainy:
Console.WriteLine("下雨了。别忘了带伞!");
break;
case WeatherCondition.Stormy:
Console.WriteLine("暴风雨!最好宅家里。");
break;
case WeatherCondition.Snowy:
Console.WriteLine("下雪啦——记得戴帽子!");
break;
default:
Console.WriteLine("未知天气...");
break;
}
- 每个case对应一个枚举值。
- 如果没匹配到任何已知选项,就会走default(比如变量里进了个奇怪的值)。
为啥enum+switch这么香?
- 代码好读:所有可能的选项一目了然。
- 扩展方便:加了新天气类型,直接多写一个case就行。
- 更安全:编译器会提醒你是不是漏处理了某些情况(C# 8.0起还能强制检查全覆盖)。
例子:游戏里的状态枚举
public enum GameState
{
Start,
Playing,
Paused,
GameOver
}
void PrintState(GameState state)
{
switch (state)
{
case GameState.Start:
Console.WriteLine("欢迎来到游戏!");
break;
case GameState.Playing:
Console.WriteLine("游戏进行中。加油!");
break;
case GameState.Paused:
Console.WriteLine("暂停。可以休息下。");
break;
case GameState.GameOver:
Console.WriteLine("游戏结束。再来一次吧!");
break;
default:
Console.WriteLine("未知游戏状态。");
break;
}
}
小建议:
- 如果有好几个选项要做一样的事,可以合并:
switch (today)
{
case WeatherCondition.Rainy:
case WeatherCondition.Stormy:
Console.WriteLine("别忘了带伞和穿暖点!");
break;
}
- 别忘了写default,防止遇到奇怪的值(比如有人直接把数字转成enum)。
- 用switch做“状态机”、菜单、各种固定选项的系统都很方便。
8. 枚举和.NET的常用方法/服务
.NET给枚举提供了很多好用的方法:
- Enum.GetNames(typeof(WeatherCondition)) —— 获取所有名字。
- Enum.GetValues(typeof(WeatherCondition)) —— 获取所有值。
- Enum.IsDefined(typeof(WeatherCondition), "Rainy") —— 判断枚举里有没有这个成员。
- 文档:System.Enum
例子:打印所有天气选项
foreach (var name in Enum.GetNames(typeof(WeatherCondition)))
{
Console.WriteLine(name);
}
9. 常见错误和“坑”
- 用“魔法数字”代替枚举,代码难读。
- 没处理枚举里没定义的值(见前面数字强转enum的例子)。
- 枚举成员名字没意义(Value1、Value2……过一阵谁都忘了啥意思)。
- 一个枚举里混着不同类型的东西,违反单一职责原则。
最好的做法:只要有固定选项就用枚举,成员名字一定要有意义、能自解释。
GO TO FULL VERSION