1. 前言
寫程式時常常會遇到一堆已知、有限的選項清單。像是:一週的天數、紅綠燈顏色、遊戲難度等級、訂單狀態。這些選項通常都對應到固定的值。這時候就要來聊聊今天的主題——列舉(enum)。
列舉就是一種特殊的資料型別,讓你可以宣告一組有名字的常數。
enum 就像一個有分格子的盒子,每個格子貼著標籤,每個標籤都是唯一的名字,對應到一個數字。
- 你的 code 會變得超好讀又自帶說明;
- 不再有什麼神祕的「魔法數字」像 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——一個會根據天氣反應的 console 程式。
// 應用程式類別
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 的實務應用場景
列舉會在哪裡遇到?
- 商業 app:訂單狀態(New、Processing、Shipped、Cancelled)。
- 用戶管理系統:權限等級(User、Moderator、Admin)。
- 遊戲:角色狀態(Idle、Moving、Jumping、Falling)。
- GUI:按鈕、訊息、icon 顏色。
如果你有深入 .NET,你會發現標準函式庫裡幾乎一半的 class 都有用到列舉!像檔案操作就有列舉來指定開檔模式(讀、寫、建立)。
5. 明確指定值與數值範圍
有時候你想把一組 int 轉成 enum,超簡單:
public enum CompassDirection
{
North = 10,
East = 20,
South = 30,
West = 40
}
現在 CompassDirection.North = 10,East = 20,以此類推。如果有元素沒指定,會自動比前一個多 1。
儲存型別
預設 enum 是 int(4 bytes 整數)。但你想省記憶體也可以自己指定底層型別:
public enum TinyEnum : byte
{
First, // 0
Second, // 1
Third // 2
}
這樣每個列舉值只佔一個 byte!
可以用的型別有:byte、sbyte、short、ushort、int、uint、long、ulong。
6. enum 跟數字/字串的轉換
enum ↔ int 轉換:
要把 enum 轉 int 或反過來,只要 typecast 就好:
WeatherCondition current = WeatherCondition.Cloudy;
int number = (int)current; // 會拿到 1
WeatherCondition fromNumber = (WeatherCondition)2; // 會拿到 Rainy
enum ↔ string 轉換:
enum 轉字串超 easy:直接呼叫 ToString()。
// enum 轉字串
string name = WeatherCondition.Stormy.ToString(); // "Stormy"
// 用 Enum.Parse 把字串轉 enum
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"!)
所以寫 code 的時候要小心這種轉換。
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)。
為什麼 enum + switch 這麼棒?
- 超好讀:所有可能的狀態一目了然。
- 好擴充:加新天氣就多一個 case。
- 安全:編譯器會提醒你沒處理到所有狀態(C# 8.0 以後還能強制檢查)。
範例:遊戲用 enum + switch 實作邏輯
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. 常見錯誤跟「地雷」
- 用「魔法數字」而不用列舉,結果 code 超難讀。
- 沒處理列舉裡沒定義的值(像直接轉型的情況)。
- 列舉元素亂取名(Value1、Value2...,過一陣子誰都忘了這是啥)。
- 一個列舉塞一堆不相關的東西,違反單一職責原則。
最好的做法:只要有固定選項就用列舉,然後每個元素都要有意義、能自我說明的名字。
GO TO FULL VERSION