1. Giới thiệu
Khi lập trình, tụi mình hay phải làm việc với danh sách các lựa chọn đã biết trước, giới hạn sẵn. Ví dụ: các ngày trong tuần, màu đèn giao thông, mức độ khó của game, trạng thái đơn hàng. Mỗi lựa chọn này thường là một giá trị cố định. Đó chính là lúc chủ đề hôm nay xuất hiện — enum (enum).
Enum là một kiểu dữ liệu đặc biệt cho phép khai báo tập hợp các hằng số có tên.
enum giống như một cái hộp chia ngăn, mỗi ngăn là một nhãn tên riêng biệt gắn với một số nguyên.
- Code của bạn sẽ dễ đọc và tự giải thích hơn;
- Thay vì mấy con số bí ẩn kiểu 0, 1, 2 thì có tên rõ ràng: DayOfWeek.Monday hoặc TrafficLight.Red;
- Compiler sẽ báo lỗi nếu bạn gán giá trị không hợp lệ;
- Thực ra mỗi phần tử enum chỉ là... số nguyên bình thường thôi! (Chút nữa sẽ nói kỹ hơn.)
2. Cú pháp khai báo enum
Làm thử enum đầu tiên nhé — các kiểu thời tiết cho app tương lai của tụi mình. Nó sẽ như này:
// Enum điều kiện thời tiết
public enum WeatherCondition
{
Sunny, // 0
Cloudy, // 1
Rainy, // 2
Stormy, // 3
Snowy // 4
}
- Từ khóa enum tạo ra kiểu mới.
- Trong dấu ngoặc nhọn là tên các lựa chọn. Mặc định, mỗi lựa chọn sẽ được gán số nguyên bắt đầu từ 0 (Sunny == 0, Cloudy == 1 v.v.).
- Bạn có thể gán giá trị cụ thể luôn:
public enum WeatherCondition
{
Sunny = 1,
Cloudy = 2,
Rainy = 4,
Stormy = 8,
Snowy = 16
}
Cái này tiện nếu bạn cần enum khớp với chuẩn hoặc protocol bên ngoài nào đó.
3. Sử dụng enum
Giả sử tụi mình viết một app nhỏ — chương trình console phản ứng theo thời tiết.
// Lớp ứng dụng
class Program
{
static void Main()
{
// Dùng enum để lưu trạng thái thời tiết
WeatherCondition todayWeather = WeatherCondition.Sunny;
// In ra màn hình
Console.WriteLine($"Hôm nay thời tiết: {todayWeather} ({(int)todayWeather})");
// Giả lập đổi thời tiết
todayWeather = WeatherCondition.Rainy;
Console.WriteLine($"Ôi! Thời tiết đã đổi: {todayWeather} ({(int)todayWeather})");
}
}
Chuyện gì sẽ xảy ra?
Hôm nay thời tiết: Sunny (0)
Ôi! Thời tiết đã đổi: Rainy (2)
- todayWeather không phải string, không phải số, mà là phần tử enum.
- Ép kiểu sang (int) để xem mã số của giá trị đó.
Enum dùng với điều kiện cũng rất ổn:
if (todayWeather == WeatherCondition.Rainy)
Console.WriteLine("Mang dù theo nha!");
4. Các tình huống thực tế dùng enum
Enum xuất hiện ở đâu?
- App doanh nghiệp: trạng thái đơn hàng (New, Processing, Shipped, Cancelled).
- Hệ thống quản lý user: cấp quyền (User, Moderator, Admin).
- Game: trạng thái nhân vật (Idle, Moving, Jumping, Falling).
- GUI: nút bấm, thông báo, màu icon.
Nếu bạn tìm hiểu sâu về .NET — gần như class nào trong thư viện chuẩn cũng có enum! Ví dụ, thao tác file có enum để chỉ mode mở file (đọc, ghi, tạo mới).
5. Giá trị tường minh và phạm vi giá trị
Đôi khi bạn muốn chuyển một tập int trong code thành enum. Làm rất dễ:
public enum CompassDirection
{
North = 10,
East = 20,
South = 30,
West = 40
}
Bây giờ CompassDirection.North = 10, East = 20, v.v. Nếu phần tử nào không gán giá trị, nó sẽ tự động lấy giá trị trước đó +1.
Kiểu lưu trữ
Mặc định enum lưu dưới dạng int (4 byte). Nhưng bạn có thể chọn kiểu khác nếu muốn tiết kiệm bộ nhớ:
public enum TinyEnum : byte
{
First, // 0
Second, // 1
Third // 2
}
Bây giờ mỗi giá trị enum chỉ chiếm 1 byte thôi!
Các kiểu có thể dùng: byte, sbyte, short, ushort, int, uint, long, ulong.
6. Chuyển đổi giữa enum và số/chuỗi
Chuyển đổi enum ↔ int:
Để chuyển enum sang int và ngược lại, chỉ cần ép kiểu:
WeatherCondition current = WeatherCondition.Cloudy;
int number = (int)current; // Sẽ ra 1
WeatherCondition fromNumber = (WeatherCondition)2; // Sẽ ra Rainy
Chuyển đổi enum ↔ string:
Chuyển enum sang string thì gọi ToString() là xong.
// Chuyển enum thành chuỗi
string name = WeatherCondition.Stormy.ToString(); // "Stormy"
// Chuyển chuỗi thành enum bằng Enum.Parse
WeatherCondition parsed = (WeatherCondition)Enum.Parse(typeof(WeatherCondition), "Stormy");
// Hoặc dùng Enum.TryParse
WeatherCondition parsedOk;
if (Enum.TryParse("Snowy", out parsedOk))
{
Console.WriteLine(parsedOk); // Snowy
}
Lỗi thường gặp:
Nếu bạn ép một số thành enum mà enum không có phần tử đó, compiler không báo lỗi, nhưng bạn sẽ nhận được trạng thái "ảo".
Ví dụ:
WeatherCondition weird = (WeatherCondition)999;
Console.WriteLine(weird); // 999 (nó không thành "Unknown" đâu!)
Nên lập trình viên phải cẩn thận khi chuyển đổi kiểu như vậy.
7. switch và enum sinh ra cho nhau
Enum (enum) kết hợp với switch cực kỳ hợp lý. Đây là cách gọn gàng, dễ hiểu để "phản ứng" với các giá trị enum — không cần if-else dài dòng.
Ví dụ: phản ứng theo thời tiết
public enum WeatherCondition
{
Sunny,
Cloudy,
Rainy,
Stormy,
Snowy
}
WeatherCondition today = WeatherCondition.Rainy;
switch (today)
{
case WeatherCondition.Sunny:
Console.WriteLine("Trời nắng! Đi chơi thôi.");
break;
case WeatherCondition.Cloudy:
Console.WriteLine("Trời âm u. Mang áo khoác nhẹ.");
break;
case WeatherCondition.Rainy:
Console.WriteLine("Trời mưa. Đừng quên dù nha!");
break;
case WeatherCondition.Stormy:
Console.WriteLine("Bão! Ở nhà cho an toàn.");
break;
case WeatherCondition.Snowy:
Console.WriteLine("Tuyết rơi — nhớ đội mũ!");
break;
default:
Console.WriteLine("Thời tiết không xác định...");
break;
}
- Mỗi case ứng với một giá trị enum.
- Nếu giá trị không khớp cái nào, sẽ chạy default (hữu ích nếu ai đó gán số lạ vào enum).
Tại sao enum + switch lại ngon?
- Dễ đọc: tất cả lựa chọn đều hiện rõ qua các case.
- Dễ mở rộng: thêm kiểu thời tiết mới — chỉ cần thêm case nữa.
- An toàn: compiler sẽ cảnh báo nếu bạn quên xử lý hết các trường hợp (từ C# 8.0 có thể bật kiểm tra exhaustive).
Ví dụ: enum cho logic game
public enum GameState
{
Start,
Playing,
Paused,
GameOver
}
void PrintState(GameState state)
{
switch (state)
{
case GameState.Start:
Console.WriteLine("Chào mừng đến với game!");
break;
case GameState.Playing:
Console.WriteLine("Game đang chạy. Chúc may mắn!");
break;
case GameState.Paused:
Console.WriteLine("Tạm dừng. Nghỉ chút đi.");
break;
case GameState.GameOver:
Console.WriteLine("Game over. Thử lại nhé!");
break;
default:
Console.WriteLine("Trạng thái game không xác định.");
break;
}
}
Tips:
- Nếu nhiều trường hợp xử lý giống nhau, gộp lại luôn:
switch (today)
{
case WeatherCondition.Rainy:
case WeatherCondition.Stormy:
Console.WriteLine("Nhớ mang dù và mặc ấm nha!");
break;
}
- Đừng quên default để xử lý giá trị lạ (ví dụ ai đó ép số thành enum).
- Dùng switch rất tiện để xây dựng "máy trạng thái", menu, hoặc hệ thống có lựa chọn cố định.
8. Enum và các method/service chính của .NET
.NET có nhiều method hữu ích cho enum:
- Enum.GetNames(typeof(WeatherCondition)) — lấy tất cả tên.
- Enum.GetValues(typeof(WeatherCondition)) — lấy tất cả giá trị.
- Enum.IsDefined(typeof(WeatherCondition), "Rainy") — kiểm tra enum có phần tử này không.
- Tài liệu: System.Enum
Ví dụ in ra tất cả kiểu thời tiết:
foreach (var name in Enum.GetNames(typeof(WeatherCondition)))
{
Console.WriteLine(name);
}
9. Lỗi thường gặp và "bẫy"
- Dùng "số ma" thay vì enum, làm code khó đọc.
- Không xử lý giá trị không có trong enum (xem phần ép số thành enum).
- Đặt tên phần tử enum không có ý nghĩa (Value1, Value2... — rồi chẳng ai nhớ nó là gì).
- Vi phạm nguyên tắc trách nhiệm đơn — dùng một enum cho nhiều thứ khác nhau.
Giải pháp tốt nhất: luôn dùng enum khi có tập lựa chọn cố định, và đặt tên phần tử thật ý nghĩa, tự giải thích.
GO TO FULL VERSION