Enum và nghệ thuật sử dụng

Giới thiệu về Enum

Hẳn Enum là 1 khái niệm thực sự gẫn gũi với mỗi anh/chị em lập trình viên. Enum là một tập hợp các giá trị có thể có của 1 thuộc tính, chẳng hạn Giới tính thì có thể Nam, Nữ (nay thì có thêm Gay, Less), hay tình trạng hôn nhân Status của 1 người thì có thể là Single, Engaged, Complicated, Married. Kiểu dữ liệu mặc định của Enumint, phần tử đầu tiên có giá trị là 0 và các phần tử tiếp theo có giá trị mặc định tăng lên 1.

Công dụng của Enum

public enum MaritalStatus 
{
    Single, Engaged, Complicated, Married
}

Như đoạn code khai báo ở trên thì tình trạng hôn nhân của 1 người chỉ có thể là 1 trong 4: độc thân, đã đính hôn, còn phức tạp hay đã cưới. Giá trị đại diện cho Single là 0, Engaged là 1, Complicated là 2 và Married là 3. Đó là giá trị mặc định, còn tất nhiên là chúng ta có thể tự define giá trị cho mỗi Status

public enum MaritalStatus 
{
    Single = 1 , Engaged = 3, Complicated = 5, Married = 10
}

Tác dụng của Enum có thể kể đến:

  • Giới hạn các giá trị mà 1 thuộc tính có thể có (như trên thì MaritalStatus chỉ có 4 giá trị khác nhau)
  • Enum giúp chúng ta dễ dàng nhận ra các giá trị có thể có của 1 thuộc tính, giúp dễ dàng đọc hiểu code

Vòng vo về Enum như thế đủ rồi. Phần chính của bài này mình muốn nói đến cách kết hợp Enum và Bit-Flags, Sự kết hợp hoàn hảo (tất nhiên là nên đúng nơi đúng chỗ 😄)

Kết hợp Enum và Bit-Flags

Giả sử mình quy định 1 người có những thuộc tính tốt đẹp là Đẹp Trai, Code Giỏi, và Nhiều Tiền. Một người chỉ cần có 1 trong 3 thuộc tính đó thì sẽ có người yêu. Vậy mình sẽ triển khai enum như thế nào, làm sao để mình có thể kiểm tra được là chỉ cần có 1 trong 3 thì có người yêu? 😃) Hãy suy nghĩ nhé. Trước khi đến câu trả lời thì mình xin nói qua 2 phép toán với bit là OR và AND

Phép toán OR (|)

   0001 (decimal 1)
OR 0010 (decimal 2)
 = 0011 (decimal 3)
   
    0011 (decimal 3)
 OR 0100 (decimal 4)
  = 0111 (decimal 7)

Phép toán OR sẽ cho ra kết quả là 1 **nếu một trong hai tham số có giá trị là 1. **

Phép toán AND (&)

    0101 (decimal 5)
AND 0011 (decimal 3)
  = 0001 (decimal 1)
      
    0111 (decimal 7)
AND 1000 (decimal 8)
  = 0000 (decimal 0)

Phép toàn AND sẽ cho ra kết quả là 1 nếu cả hai tham số đều có giá trị là 1.


Như bạn thấy thì phép toán OR nếu 1 hàng dọc chỉ có một số 1 thì phép toán OR trở thành giống như phép toán cộng thông thường (1 + 2 + 4 = 7) Vậy sự kết hợp hoàn hảo ở đây là

[Flags]
public enum CoNguoiYeu
{
        ChuaMuonCo = 0,
        DepTrai = 1,
        CodeGioi = 2,
        NhieuTien = 4,
        HayAoTuong = 8
        DuTieuChuan = DepTrai | CodeGioi | NhieuTien
}

Kiểm tra

Vậy đối với 1 người chỉ cần DepTrai, CodeGioi hoặc NhieuTien thì sẽ đủ tiêu chuẩn có người yêu. Code sẽ check đơn giản:

var Ban = CoNguoiYeu.DepTrai | CoNguoiYeu.CodeGioi;
if ((Ban & CoNguoiYeu.DuTieuChuan)  != 0)
            {
                Console.WriteLine("Co");
            }
            else
            {
                Console.WriteLine("Chua co");
            }
//Co

Ở trên mình đã gán Bạn là 1 người đẹp trai và code giỏi. Sau đó mình dùng phép toán AND (&) để kiểm tra bạn có đủ tiêu chuẩn chưa. Hãy tính toán một chút nhé. Ban = CoNguoiYeu.DepTrai | CoNguoiYeu.CodeGioi = 3 (0011) CoNguoiYeu.DuTieuChuan = DepTrai | CodeGioi | NhieuTien = 7 (0111) Chỉ cần lấy 2 kết quả và thực hiện phép toàn AND. Kết quả trả về khác 0, tức là có ít nhất 1 hàng dọc có 2 số 1, thỏa điều kiện. Vậy là đủ tiêu chuẩn 😄

    0011 (decimal 3)
AND 0111 (decimal 7)
  = 0011 (decimal 3)

Ví dụ khác trả về kết quả sẽ là không có:

var Ban = CoNguoiYeu.HayAoTuong;
if ((Ban & CoNguoiYeu.DuTieuChuan)  != 0)
            {
                Console.WriteLine("Co");
            }
            else
            {
                Console.WriteLine("Chua co");
            }
//Chua co
    0111 (decimal 7)
AND 1000 (decimal 8)
  = 0000 (decimal 0)

Không có số 1 nào trùng nhau nên kết quả của phép tính AND là 0. Kết quả sẽ in ra là Chưa có 😄

Như vậy, có thể thấy nếu chúng ta áp dụng bitwise operation vào Enum, với các giá trị theo hệ nhị phân tăng dần theo số mũ, ta có thể kiểm tra được 1 vài điều kiện nhanh và ngắn gọn. Các bạn cũng có thể sử dụng hệ cơ số khác và thử áp dụng.

Kết bài

Tất nhiên những ví dụ ở trên chỉ mang tính giải trí. Nhưng qua những ví dụ trên chúng ta có thể thấy việc ứng dụng bitwise vào enum thông minh sẽ làm cho code chúng ta trở nên ngắn gọn và tường minh hơn. Mình hy vọng bài viết bổ ích. Cảm ơn các bạn đã đọc bài.


Bài viết sử dụng cú pháp của C# và có tham khảo một số nguồn dưới đây: http://geekswithblogs.net/BlackRabbitCoder/archive/2010/07/22/c-fundamentals-combining-enum-values-with-bit-flags.aspx https://www.mindstick.com/Articles/329/enumeration-in-c-sharp# https://en.wikipedia.org/wiki/Bitwise_operation