sai giá trị enum trong C # [trùng lặp]

Sep 09 2020

Tại sao in sau đây EOFlà đầu ra mà không phải là đầu ra ILLEGAL? Nếu tôi xóa phần khởi tạo cho ký tự EOF thành NULL, nó hoạt động như mong đợi. Không thể hiểu chuyện gì đang xảy ra ở đây?

public enum TokenType {
            ILLEGAL,
            EOF= '\0',//remove the initialization to have it work as expected
            IDENT,
            INT
            };

void Main()
{
    Console.WriteLine(TokenType.ILLEGAL);//Prints EOF. Should have printed ILLEGAL
}

Trả lời

4 Sweeper Sep 09 2020 at 07:06

Đầu tiên, lưu ý rằng = '\0'giống như = 0. Điều này là do '\0'có giá trị số bằng 0. Enum của bạn có kiểu cơ bản mặc định là int. Biểu thức hằng '\0'được chuyển đổi thành intcủa 0tại thời điểm biên dịch.

Thứ hai, theo thông số ngôn ngữ , lưu ý rằng các thành viên enum có thể có các giá trị liên kết trùng lặp.

Thứ ba, từ cùng một phần của thông số ngôn ngữ,

Giá trị liên kết của một thành viên enum được chỉ định ngầm hoặc rõ ràng. [...] Nếu khai báo thành viên enum không có bộ khởi tạo, giá trị liên kết của nó được đặt ngầm định, như sau:

  • Nếu thành viên enum là thành viên enum đầu tiên được khai báo trong kiểu enum, giá trị liên kết của nó bằng không.

  • Nếu không, giá trị liên kết của thành viên enum nhận được bằng cách tăng giá trị liên kết của thành viên enum trước đó lên một. Giá trị gia tăng này phải nằm trong phạm vi giá trị có thể được đại diện bởi kiểu cơ bản, nếu không sẽ xảy ra lỗi thời gian biên dịch.

Vì vậy, nếu tôi viết ra các giá trị liên kết của các thành viên enum của bạn một cách rõ ràng, nó sẽ là:

public enum TokenType {
        ILLEGAL = 0,
        EOF = 0,
        IDENT = 1,
        INT = 2
        };

ILLEGALvà EOFcó cùng giá trị liên kết.

Thứ tư, Console.WriteLinecác cuộc gọi ToStringtrên enum của bạn. Bây giờ hãy xem những gì Enum.ToStringhiện (trong phần Ghi chú cho Người gọi):

Nếu nhiều thành viên liệt kê có cùng giá trị cơ bản và bạn cố gắng truy xuất biểu diễn chuỗi của tên thành viên liệt kê dựa trên giá trị cơ bản của nó, thì mã của bạn không nên đưa ra bất kỳ giả định nào về tên mà phương thức sẽ trả về.

Vì vậy, việc xuất ra ILLEGALlà hoàn toàn bình thường, vì bạn "không nên đưa ra bất kỳ giả định nào về tên mà phương thức sẽ trả về".

5 MongZhu Sep 09 2020 at 06:52

Bằng cách khởi tạo EOFgiá trị bằng '\ 0', bạn cung cấp cho nó một giá trị 0.

Bạn có thể thấy điều này trong ví dụ này:

Console.WriteLine(Convert.ToInt16(TokenType.EOF));
Console.WriteLine($"IntValue: {Convert.ToInt16('\0')}");

0
IntValue: 0

Bên trong enum sẽ nhận các giá trị bắt đầu từ 0 khi đếm trở lên theo số nguyên. Vì vậy, bên dưới bề mặt enum của bạn trông như thế này:

public enum TokenType
{
    ILLEGAL = 0,
    EOF = 1
    IDENT = 2,
    INT = 3
};

Nhưng bạn đã chọn thực thi 0trên giá trị EOF! Vì vậy, bạn có 2 tên enum đại diện cho cùng một giá trị. Trình biên dịch chỉ cần lấy cái đầu tiên mà nó có thể tìm thấy.

1 DervişKayımbaşıoğlu Sep 09 2020 at 07:01

điều này giải thích cho việc sắp xếp

foreach (Enum e in Enum.GetValues(typeof(TokenType)))
    Console.WriteLine("{0}: {1}", e, Convert.ToInt16(e));

Console.WriteLine();

foreach (Enum e in Enum.GetValues(typeof(Another_TokenType)))
    Console.WriteLine("{0}: {1}", e, Convert.ToInt16(e));


EOF: 0
EOF: 0
IDENT: 1
INT: 2

ILLEGAL: 0
ILLEGAL: 0
EOF: 1
IDENT: 2

'\ 0' dẫn đến giá trị 0 khi được chuyển đổi thành int. và cờ enum được khởi tạo không có giá trị đầu tiên cũng có giá trị 0.