openplanning

Hướng dẫn và ví dụ C# Enum

  1. C# Enum là gì?
  2. Có thể sử dụng toán tử == để so sánh các phần tử của enum
  3. Duyệt trên các phần tử của Enum
  4. Enum và Attribute
  5. Enum có thể có phương thức hay không?

1. C# Enum là gì?

enum trong C# là một từ khóa, nó sử dụng để khai báo một tập hợp kiểu liệt kê (enumeration).
Giờ chúng ta cần xem nếu không có Enum trong một số tình huống bạn phải làm thế nào, chẳng hạn bạn cần một tập hợp chứa các ngày trong tuần. Thông thường bạn định nghĩa ra 7 hằng số tự nhiên để đại diện cho 7 trong tuần.
WeekDayConstants.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    class WeekDayConstants
    {
         public const int MONDAY = 2;
         public const int TUESDAY = 3;
         public const int WEDNESDAY = 4;
         public const int THURSDAY = 5;

         public const int FRIDAY = 6;
         public const int SATURDAY = 7;
         public const int SUNDAY = 1;
    }
}
Một class với một method mô phỏng lấy ra tên công việc sẽ làm ứng với ngày cụ thể trong tuần. (Giống với thời khóa biểu)
Timetable.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
   // Thời khóa biểu.
   class Timetable
   {
       // Tham số truyền vào là ngày trong tuần.
       // Trả về tên công việc sẽ làm.
       public static String getJob(int dayInWeek)
       {
           if (dayInWeek == WeekDayConstants.SATURDAY
                   || dayInWeek == WeekDayConstants.SUNDAY)
           {
               return "Nothing";
           }
           return "Coding";
       }
   }
}
Rõ ràng các đoạn mã như vậy là không an toàn. Chẳng hạn như khi bạn gõ các giá trị cho ngày trong tuần chẳng may trùng nhau. Hoặc khi gọi phương thức Timetable.getJob(int) mà truyền vào giá trị nằm ngoài các giá trị định nghĩa trước.
  • Không phải là kiểu an toàn: Đầu tiên thấy rằng mã (code) của bạn không an toàn, bạn có thể gọi phương thức GetJob(int) và truyền vào bất kỳ giá trị nào.
  • Không có ý nghĩa trong in ấn: Nếu bạn muốn in ra các ngày trong tuần nó sẽ là các con số,thay vì một chữ có ý nghĩa như "MONDAY".
Và đây là cách sử dụng Enum để định nghĩa ra các ngày trong tuần.
WeekDay.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    public enum WeekDay
    {
       MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
}
Và ví dụ sử dụng enum WeekDay:
Timetable2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    class Timetable2
    {
        public static String getJob(WeekDay weekDay)
        {
            if (weekDay == WeekDay.SATURDAY || weekDay == WeekDay.SUNDAY)
            {
                return "Nothing";
            }
            return "Coding";
        }
    }
}

2. Có thể sử dụng toán tử == để so sánh các phần tử của enum

Enum là một đối tượng tham chiếu (reference object) giống như class, interface nhưng nó cũng có thể sử dụng cách so sánh ==.
Hãy xem các đối tượng tham chiếu (reference object) so sánh thế nào:
// Để so sánh các đối tượng tham chiếu thông thường phải sử dụng method equals(..)
object obj1 = ...;

// So sánh đối tượng với null, có thể sử dụng toán tử ==
if (obj1 == null)
{

}

object obj2 = ...;

// So sánh khác null.
if (obj1 != null)
{
   // So sánh 2 đối tượng với nhau.
   if (obj1.Equals(obj2))
   {

   }
}
Với Enum, bạn có thể sử dụng toán tử == để so sánh.
CompareEnumDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
  class CompareEnumDemo
  {
      public static void Main(string[] args)
      {
          WeekDay today = WeekDay.SUNDAY;
          // Sử dụng toán tử == để so sánh 2 phần tử của Enum.
          if (today == WeekDay.SUNDAY)
          {
              Console.WriteLine("Today is Sunday");
          }
          Console.Read();
      }
  }
}

3. Duyệt trên các phần tử của Enum

Chúng ta có thể duyệt trên tất cả các phần tử của Enum. Xem ví dụ minh họa:
ValuesDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    class ValuesDemo
    {
        public static void Main(string[] args)
        {
            // Lấy ra tất cả các phần tử của Enum.
            Array allDays = Enum.GetValues(typeof(WeekDay));
            foreach (WeekDay day in allDays)
            {
                Console.WriteLine("Day: " + day);
            }
            Console.Read();
        }     
    }
}
Kết quả chạy ví dụ:
Day: MONDAY
Day: TUESDAY
Day: WEDNESDAY
Day: THURSDAY
Day: FRIDAY
Day: SATURDAY
Day: SUNDAY

4. Enum và Attribute

Bạn có thể gắn các Attribute lên các phần tử của Enum, điều này giúp cho Enum mang nhiều thông tin hơn, và bạn có thể lấy ra các thông tin đó ứng với từng phần tử của Enum.
Xem thêm:
  • Hướng dẫn và ví dụ C# Attribute
GenderAttr.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    class GenderAttr : Attribute
    {
        // code: M, text = Male
        // code: F, text = Female
        internal GenderAttr(string code, string text)
        {
            this.Code = code;
            this.Text = text;
        }
        public string Code { get; private set; }
        public string Text { get; private set; }  
    }
}
enum Gender (Giới tính) có 2 phần tử MALE (Nam) và FEMALE (Nữ).
Gender.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
   public enum Gender
   {
       // Một phần tử của Enum, có thuộc tính
       [GenderAttr("M","Male")]
       MALE,
       // Một phần tử của Enum, có thuộc tính
       [GenderAttr("F","Female")]
       FEMALE
   }
}
Genders.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace CSharpEnumTutorial
{
   class Genders
   {
       // Trả về Gender ứng với code.
       // (Phương thức này có thể trả về null).
       public static Gender? GetGenderByCode(string code)
       {
           // Lấy hết tất cả các phần tử của Enum.
           Array allGenders = Enum.GetValues(typeof(Gender));
           foreach (Gender gender in allGenders)
           {
               string c = GetCode(gender);
               if (c == code)
               {
                   return gender;
               }
           }
           return null;
       }
       public static string GetText(Gender gender)
       {
           GenderAttr genderAttr = GetAttr(gender);
           return genderAttr.Text;
       }
       public static string GetCode(Gender gender)
       {
           GenderAttr genderAttr = GetAttr(gender);
           return genderAttr.Code;
       }
       private static GenderAttr GetAttr(Gender gender)
       {
           MemberInfo memberInfo = GetMemberInfo(gender);
           return (GenderAttr)Attribute.GetCustomAttribute(memberInfo, typeof(GenderAttr));
       }
       private static MemberInfo GetMemberInfo(Gender gender)
       {
           MemberInfo memberInfo
               = typeof(Gender).GetField(Enum.GetName(typeof(Gender), gender));

           return memberInfo;
       }
   }
}
Và ví dụ sử dụng enum Gender:
GenderTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
    class GenderTest
    {
        public static void Main(string[] args)
        {
            Gender marryGender = Gender.FEMALE;
            Console.WriteLine("marryGender: " + marryGender);
            Console.WriteLine("Code: " + Genders.GetCode(marryGender)); // F
            Console.WriteLine("Text: " + Genders.GetText(marryGender)); // Femate 
            String code = "M";
            Console.WriteLine("Code: " + code);
            // Phương thức có thể trả về null.
            Gender? gender = Genders.GetGenderByCode(code);
            Console.WriteLine("Gender by code: " + gender);
            Console.Read();
        }
    }
}
Chạy ví dụ:
marryGender: FEMALE
Code: F
Text: Female
Code: M
Gender by code: MALE

5. Enum có thể có phương thức hay không?

Trong C# enum không thể có phương thức, tuy nhiên trong trường hợp bạn muốn có một cái gì đó giống như Enum và có phương thức bạn có thể định nghĩa một class, class này không cho phép tạo thêm các đối tượng ngoài các đối tượng đã được tạo sẵn của nó.
GenderX.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpEnumTutorial
{
   class GenderX
   {
       public static readonly GenderX MALE = new GenderX("M","Male");
       public static readonly GenderX FEMALE = new GenderX("F","Female");
       private string code;
       private string text;

       // Cấu tử (Constructor) private: Không cho phép tạo đối tượng từ bên ngoài class.
       private GenderX(string code, string text)
       {
           this.code = code;
           this.text = text;
       }
       public string GetCode()
       {
           return this.code;
       }
       public string GetText()
       {
           return this.text;
       }
       public static GenderX GetGenderByCode(string code)
       {
           if (MALE.code.Equals(code))
           {
               return MALE;
           }
           else if (FEMALE.code.Equals(code))
           {
               return FEMALE;
           }
           return null;
       }
   } 
}