Mục lục C#

Docs / C#

Enum trong C#

Enum (enumeration) là một kiểu dữ liệu chỉ nhận một trong vài giá trị đặt tên sẵn. Trạng thái nhân vật là ví dụ kinh điển: đứng yên, chạy, nhảy, chết. Không có trạng thái nào khác, và enum bắt code tuân theo đúng danh sách đó.

Vấn đề: lưu trạng thái bằng chuỗi hoặc số

Cách người mới hay làm là dùng string state = "running"; hoặc int state = 1; rồi tự nhớ 1 là chạy, 2 là nhảy.

string state = "runing"; // gõ thiếu chữ n

if (state == "running")
{
    Console.WriteLine("Phát animation chạy");
}
// không in gì, và trình biên dịch không báo lỗi

Gõ sai một chữ là bug câm: code vẫn chạy, chỉ là nhân vật không bao giờ chạy. Với số thì còn tệ hơn, sáu tháng sau không ai nhớ 3 là gì.

Khai báo và dùng enum

PlayerState state = PlayerState.Idle;
Console.WriteLine(state); // Idle

state = PlayerState.Running;
Console.WriteLine(state); // Running

if (state == PlayerState.Running)
{
    Console.WriteLine("Phát animation chạy");
}
// Phát animation chạy

enum PlayerState
{
    Idle,
    Running,
    Jumping,
    Dead
}

Giờ gõ sai PlayerState.Runing là lỗi biên dịch ngay, không đợi tới lúc chơi mới phát hiện. Viết PlayerState. trong editor còn được gợi ý đủ danh sách.

Giống class, enum trong top-level statements phải khai báo ở cuối file, sau code chạy, không thì gặp lỗi CS8803.

Lỗi hay gặp: so sánh enum với chuỗi, như if (state == "Running"). C# báo CS0019 "Operator '==' cannot be applied to operands of type 'PlayerState' and 'string'". Luôn so với PlayerState.Running.

Switch trên enum

Enum đi cùng switch rất tự nhiên: mỗi trạng thái một case.

PlayerState state = PlayerState.Jumping;

switch (state)
{
    case PlayerState.Idle:
        Console.WriteLine("Đứng thở");
        break;
    case PlayerState.Running:
        Console.WriteLine("Chạy, tốc độ 6");
        break;
    case PlayerState.Jumping:
        Console.WriteLine("Đang trên không, không nhảy thêm được");
        break;
    case PlayerState.Dead:
        Console.WriteLine("Hiện màn hình Game Over");
        break;
}
// Đang trên không, không nhảy thêm được

enum PlayerState
{
    Idle,
    Running,
    Jumping,
    Dead
}

Với trường hợp chỉ cần trả về một giá trị, switch expression gọn hơn:

PlayerState state = PlayerState.Running;

float speed = state switch
{
    PlayerState.Running => 6f,
    PlayerState.Jumping => 4f,
    _ => 0f
};
Console.WriteLine(speed); // 6

enum PlayerState
{
    Idle,
    Running,
    Jumping,
    Dead
}

_ là nhánh mặc định cho mọi trạng thái còn lại.

Enum là số nguyên bên dưới

Mỗi giá trị enum thật ra là một int, bắt đầu từ 0 theo thứ tự khai báo. Ép kiểu để xem hoặc chuyển ngược lại.

Console.WriteLine((int)PlayerState.Jumping); // 2

PlayerState loaded = (PlayerState)3;
Console.WriteLine(loaded); // Dead

enum PlayerState
{
    Idle,
    Running,
    Jumping,
    Dead
}

Bạn có thể tự gán số. Việc này hữu ích khi giá trị có ý nghĩa, như độ hiếm của vật phẩm ảnh hưởng tới giá bán:

Rarity rarity = Rarity.Epic;
int sellPrice = 10 * (int)rarity;
Console.WriteLine($"{rarity}: {sellPrice} vàng"); // Epic: 250 vàng

enum Rarity
{
    Common = 1,
    Rare = 5,
    Epic = 25,
    Legendary = 100
}

Lưu ý khi lưu game: nếu bạn lưu enum dưới dạng số rồi sau này chèn giá trị mới vào giữa danh sách, các số phía sau bị dịch đi và file save cũ đọc sai. Thêm giá trị mới vào cuối, hoặc gán số cố định như ví dụ Rarity.

Trong Unity

Field kiểu enum public hoặc có [SerializeField] hiện trong Inspector dưới dạng danh sách thả xuống. Đây là cách gọn để designer chọn loại quái, loại vũ khí mà không gõ chuỗi.

Bài tập

Tạo enum Weather gồm Sunny, Rain, Storm. Viết switch expression trả về hệ số tầm nhìn: Sunny là 1.0, Rain là 0.5, Storm là 0.25. In tầm nhìn khi thời tiết là Rain với tầm nhìn gốc là 50.

Xem đáp án
Weather weather = Weather.Rain;
float baseView = 50f;

float factor = weather switch
{
    Weather.Sunny => 1.0f,
    Weather.Rain => 0.5f,
    Weather.Storm => 0.25f,
    _ => 1.0f
};

Console.WriteLine($"{weather}: tầm nhìn {baseView * factor}"); // Rain: tầm nhìn 25

enum Weather
{
    Sunny,
    Rain,
    Storm
}