Không ai trong số họ nên biên dịch. Đặc tả C# yêu cầu một phần chuyển đổi có ít nhất một câu lệnh. Trình phân tích cú pháp sẽ không cho phép nó.
Hãy bỏ qua thực tế là trình phân tích cú pháp cho phép danh sách câu lệnh trống; đó không phải là những gì có liên quan. Đặc điểm kỹ thuật nói rằng phần cuối của phần chuyển đổi không được có điểm kết thúc có thể truy cập; đó là bit liên quan.
Trong ví dụ cuối cùng của bạn, phần switch có một điểm cuối có thể truy cập:
void M(int x) { switch(2) { case 2: ; } }
vì vậy nó phải là một lỗi.
Nếu bạn có:
void M(int x) { switch(x) { case 2: ; } }
sau đó trình biên dịch không biết nếu x bao giờ sẽ được 2. Nó giả định thận trọng rằng nó có thể, và nói rằng phần có điểm cuối có thể truy cập, vì trường hợp chuyển đổi nhãn là có thể truy cập.
Nếu bạn có
void M(int x) { switch(1) { case 2: ; } }
Sau đó, trình biên dịch có thể lý do đó các thiết bị đầu cuối là không thể truy cập bởi vì nhãn trường hợp là không thể truy cập. Trình biên dịch biết rằng hằng số 1 không bao giờ bằng hằng số 2.
Nếu bạn có:
void M(int x) { switch(x = 1) { case 2: ; } }
hoặc
void M(int x) { x = 1; switch(x) { case 2: ; } }
Sau đó, bạn biết và tôi biết rằng điểm cuối không phải là có thể truy cập, nhưng trình biên dịch không biết điều đó. Quy tắc trong đặc tả là khả năng tiếp cận chỉ được xác định bằng cách phân tích các biểu thức liên tục. Bất kỳ biểu thức nào có chứa biến, ngay cả khi bạn biết giá trị của nó bằng một số phương tiện khác, không phải là một biểu thức liên tục.
Trong quá khứ trình biên dịch C# có lỗi trong trường hợp này không phải như vậy. Bạn có thể nói những điều như:
void M(int x) { switch(x * 0) { case 2: ; } }
và trình biên dịch sẽ lý do x * 0 phải bằng 0, do đó không thể truy cập nhãn trường hợp. Đó là một lỗi mà tôi đã sửa trong C# 3.0. Các đặc điểm kỹ thuật nói rằng chỉ chỉ hằng số được sử dụng cho phân tích đó, và x
là một biến, không phải là một hằng số.
Bây giờ, nếu chương trình là hợp pháp thì trình biên dịch có thể sử dụng các kỹ thuật nâng cao như thế này để tác động đến mã được tạo ra. Nếu bạn nói điều gì đó như:
void M(int x) { if (x * 0 == 0) Y(); }
Sau đó, trình biên dịch có thể tạo ra các mã như thể bạn đã viết
void M(int x) { Y(); }
nếu nó muốn.Nhưng nó không thể sử dụng thực tế rằng x * 0 == 0
là đúng cho các mục đích xác định khả năng tiếp cận tuyên bố.
Cuối cùng, nếu bạn có
void M(int x) { if (false) switch(x) { case 2: ; } }
sau đó chúng ta đều biết rằng việc chuyển đổi là không thể truy cập, do đó khối không có một điểm cuối có thể truy cập, vì vậy đây là, đáng ngạc nhiên, luật pháp. Nhưng với các cuộc thảo luận ở trên, bây giờ bạn biết rằng
void M(int x) { if (x * 0 != 0) switch(x) { case 2: ; } }
không đối xử với x * 0 != 0
như false
, vì vậy điểm cuối được coi là có thể truy cập.
Có thể trình biên dịch có thể tối ưu hóa chương trình đầu tiên, nhưng không thể xóa trình biên dịch thứ hai, vì nhiệm vụ này. –
Đoán của tôi là '1' là một biểu thức liên tục được biết đến tại thời gian biên dịch, cho phép trình biên dịch tối ưu hóa toàn bộ chuyển đổi, trong khi' i = 1' là một biểu thức không liên tục (mặc dù cũng được biết đến trình biên dịch để tạo ra một giá trị cụ thể) do đó trình biên dịch cố gắng giữ nút gạt. – dasblinkenlight
Trong một thế giới lý tưởng, trình biên dịch có lẽ nên chấp nhận hoặc từ chối cả hai. Nó chắc chắn không nên tạo ra bất kỳ mã cho họ. Nhưng trong thế giới này, tôi nghĩ đó chỉ là một ví dụ khác về "Hiệu ứng Forrest Gump:" Ngu ngốc cũng ngu ngốc ":) Hỏi: Tại sao lại lãng phí thời gian/braincell thậm chí thảo luận về nó? – paulsm4