CodeGym /課程 /C# SELF /在 C# 中的列舉 (enum):超方便的命名常數

在 C# 中的列舉 (enum):超方便的命名常數

C# SELF
等級 10 , 課堂 4
開放

1. 前言

寫程式時常常會遇到一堆已知、有限的選項清單。像是:一週的天數、紅綠燈顏色、遊戲難度等級、訂單狀態。這些選項通常都對應到固定的值。這時候就要來聊聊今天的主題——列舉enum)。

列舉就是一種特殊的資料型別,讓你可以宣告一組有名字的常數。
enum 就像一個有分格子的盒子,每個格子貼著標籤,每個標籤都是唯一的名字,對應到一個數字。

  • 你的 code 會變得超好讀自帶說明
  • 不再有什麼神祕的「魔法數字」像 012,而是有意義的名字:DayOfWeek.MondayTrafficLight.Red
  • 如果你亂塞值,編譯器會直接罵你;
  • 其實每個元素背後…就是普通的整數!(這個等等會再講。)

2. 列舉的宣告語法

來寫個第一個列舉——天氣型態,假裝我們要做個天氣 app。長這樣:


// 天氣狀態的列舉
public enum WeatherCondition
{
    Sunny,       // 0
    Cloudy,      // 1
    Rainy,       // 2
    Stormy,      // 3
    Snowy        // 4
}
宣告列舉 WeatherCondition
  • enum 這個關鍵字就是在定義一個新型別。
  • 大括號裡面是各種選項的名字。預設每個選項會自動配一個整數,從 0 開始(Sunny == 0Cloudy == 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:訂單狀態(NewProcessingShippedCancelled)。
  • 用戶管理系統:權限等級(UserModeratorAdmin)。
  • 遊戲:角色狀態(IdleMovingJumpingFalling)。
  • GUI:按鈕、訊息、icon 顏色。

如果你有深入 .NET,你會發現標準函式庫裡幾乎一半的 class 都有用到列舉!像檔案操作就有列舉來指定開檔模式(讀、寫、建立)。

5. 明確指定值與數值範圍

有時候你想把一組 int 轉成 enum,超簡單:


public enum CompassDirection
{
    North = 10,
    East = 20,
    South = 30,
    West = 40
}
明確指定值的列舉

現在 CompassDirection.North = 10East = 20,以此類推。如果有元素沒指定,會自動比前一個多 1。

儲存型別

預設 enumint(4 bytes 整數)。但你想省記憶體也可以自己指定底層型別:

public enum TinyEnum : byte
{
    First,  // 0
    Second, // 1
    Third   // 2
}

這樣每個列舉值只佔一個 byte!

可以用的型別有:bytesbyteshortushortintuintlongulong

6. enum 跟數字/字串的轉換

enumint 轉換:

要把 enum 轉 int 或反過來,只要 typecast 就好:

WeatherCondition current = WeatherCondition.Cloudy;
int number = (int)current; // 會拿到 1

WeatherCondition fromNumber = (WeatherCondition)2; // 會拿到 Rainy

enumstring 轉換:

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. switchenum 根本天作之合

列舉(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 超難讀。
  • 沒處理列舉裡沒定義的值(像直接轉型的情況)。
  • 列舉元素亂取名(Value1Value2...,過一陣子誰都忘了這是啥)。
  • 一個列舉塞一堆不相關的東西,違反單一職責原則。

最好的做法:只要有固定選項就用列舉,然後每個元素都要有意義、能自我說明的名字。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION