Chương 19: Kiểu liệt kê
Tác giả: Sưu tầm
Khái quát
Kiểu liệt kê là hữu ích khi một giá trị trong chương trình chỉ có thể có một tập các giá trị xác định. Một điều khiển có thể chỉ có một trong bốn giá trị màu, hay một gói mạng hỗ trợ chỉ hai giao thức, là các trường hợp mà kiểu liệt kê có thể được dùng cải thiện mã.
Liệt kê các kiểu đường thẳng
Trong ví dụ sau đây, một lớp vẽ đường thẳng sử dụng kiểu liệt kê để định nghĩa các kiểu đường mà có thể vẽ:
using System;
public class Draw {
public enum LineStyle {
Solid,
Dotted,
DotDash
}
public void DrawLine(int x1, int y1, int x2, int y2, LineStyle lineStyle) {
switch (lineStyle) {
case LineStyle.Solid:
// draw solid
break;
case LineStyle.Dotted:
// draw dotted
break;
case LineStyle.DotDash:
// draw dotdash
break;
default:
throw(new ArgumentException(“Invalid line style”));
}
}
}
class Test {
public static void Main() {
Draw draw = new Draw();
draw.DrawLine(0, 0, 10, 10, Draw.LineStyle.Solid);
draw.DrawLine(5, 6, 23, 3, (Draw.LineStyle) 35);
}
}
Enum LineStyle định nghĩa các giá trị có thể được xác định cho một enum, và sau đó cũng enum đó được sử dụng trong lời gọi hàm để chỉ định kiểu của đường thẳng để vẽ.
Trong khi enum ngăn ngừa những chỉ định các giá trị ngẫu nhiên nằm ngoài vùng liệt kê, thì các giá trị có thể được chỉ định trong một enum không bị giới hạn cho các từ định danh được chỉ định trong khai báo enum. Lời gọi thứ hai đến DrawLine() là hợp lệ, nên một giá trị enum được chuyển đến một hàm vẫn phải được kiểm tra để đảm bảo nó trong phạm vi các giá trị hợp lệ. Lớp Draw ném ra một ngoại lệ đối số sai nếu đối số là sai.
Enum kiểu cơ sở
Một enum có một kiểu ở bên dưới mà nó chỉ định dung lượng được xác định cho enum đó. Các kiểu cơ sở hợp lệ cho enum là byte, sbyte, short, ushort, int, uint, long, và ulong. Nếu kiểu cơ sở không được xác định, kiểu cơ sở mặc định là int. Kiểu cơ sở được chỉ định bằng cách liệt kê kiểu cơ sở sau tên enum:
enum SmallEnum : byte {
A,
B,
C,
D
}
Việc định rõ kiểu cơ sở có thể là hữu ích nếu kích thước là cần quan tâm, hay nếu số lượng phần tử sẽ vượt hơn số cá giá trị có thể cho int.
Khởi tạo
Mặc định, giá trị của thành phần enum đầu tiên là 0, và tăng dần cho các thành phần tiếp theo sau. Các giá trị đặc biệt có thể được chỉ định theo tên thành phần như sau:
enum Values {
A = 1,
B = 5,
C = 3,
D = 42
}
Việc tính toán các giá trị cũng có thể được sử dụng, trong khi chúng chỉ phụ thuộc các giá trị hoàn toàn được định nghĩa bên trong enum:
enum Values {
A = 1,
B = 2,
C = A + B,
D = A * C + 33
}
Nếu enum được định nghĩa không có giá trị 0, nó có thể dẫn đến các vấn đề, vì 0 là giá trị khởi tạo mặc định cho enum:
enum Values {
A = 1,
B = 2,
C = A + B,
D = A * C + 33
}
class Test {
public static void Member(Values value) {
// do some processing here
}
public static void Main() {
Values value = 0;
Member(value);
}
}
Một thành phần với giá trị 0 luôn luôn nên được định nghĩa như một phần của enum.
Các enum cờ bit
Các enum có thể cũng được sử dụng như các cờ bit bằng cách chỉ định một giá trị bit khác nhau cho mỗt bit. Đây là một định nghĩa tiêu biểu:
[Flags]
enum BitValues {
NoBits = 0,
Bit1 = 0x00000001,
Bit2 = 0x00000002,
Bit3 = 0x00000004,
Bit4 = 0x00000008,
Bit5 = 0x00000010,
AllBits = 0xFFFFFFFF
}
class Test {
public static void Member(BitValues value) {
// do some processing here
}
public static void Main() {
Member(BitValues.Bit1 | BitValues.Bit2);
}
}
Đặc tính [Flags] ở trước định nghĩa enum được sử dụng để người thiết kế và trình duyệt có thể trình bày một giao diện khác cho các enum mà nó là các enum cờ. Đối với các enum như thế, nó có ý nghĩa để cho phép người sử dụng thực hiện phép OR cho vài bit với nhau, mà sẽ không có ý nghĩa cho các enum phi cờ.
Hàm Main() thực hiện phép OR cho vài bit với nhau, và sau đó trả ra một giá trị cho hàm thành phần.
Chuyển đổi kiểu
Kiểu enum có thể được chuyển đổi thành kiểu bên trong của nó và chuyển trở lại với một phép chuyển đổi kiểu tường minh:
enum Values {
A = 1,
B = 5,
C = 3,
D = 42
}
class Test {
public static void Main() {
Values v = (Values) 2;
int ival = (int) v;
}
}
Một ngoại lệ duy nhất ở đây mà một bit 0 có thể được chuyển đổi thành kiểu enum mà không cần một phép chuyển đổi. Điều này được cho phép cho nên mã sau có thể được viết:
public void DoSomething(BitValues bv) {
if (bv == 0) { }
}
Câu lệnh if sẽ phải được viết như sau
if (bv == (BitValues) 0)