2011-09-06 14 views
20

Trước đó ngày hôm nay, như tôi đã mã hóa một phương pháp và nó đánh tôi rằng tôi đã không chắc chắn chính xác lý do tại sao thành ngữ tôi đã thực hiện biên dịch. Nếu mọi thứ khác là trừu tượng đi, nó sẽ giống như thế này:Các vòng lặp vô hạn được xử lý trong .NET có phải là trường hợp đặc biệt không?

private int Example() 
    { 
     while (true) 
     { 
      if (some condition) 
      { 
       return 1; 
      } 
     } 
    } 

Bạn có một vòng lặp vô hạn một cách rõ ràng, và một số thiết lập các điều kiện bên trong vòng lặp mà gây ra vòng lặp kết thúc với một tuyên bố trở lại. Chúng ta hãy bỏ qua thời gian là lý do tại sao tôi đã làm điều này trái ngược với việc kiểm tra tình trạng chấm dứt trong mệnh đề while vì câu trả lời là phức tạp và không liên quan - điều tôi muốn biết là tại sao trình biên dịch không gắn cờ điều này với "Không tất cả các đường dẫn đều trả về một giá trị. " lỗi, như, nói đúng không phải tất cả các đường dẫn đều trả về một giá trị. Trường hợp trong đó vòng lặp while không bao giờ được nhập (dĩ nhiên, không bao giờ xảy ra) không trả về bất cứ thứ gì. Bây giờ, có hai lý do tôi có thể tưởng tượng nó xảy ra: đây là một tác dụng phụ của việc tối ưu hóa xảy ra vì các lý do khác, hoặc trường hợp này rõ ràng được xử lý bởi trình biên dịch để cho phép thành ngữ này. Bản năng của tôi là nó có lẽ là trường hợp đầu tiên. Ví dụ, điều này không làm tôi ngạc nhiên khi biên dịch này:

private int Example2() 
{ 
    if (true) return 1; 
} 

Bởi vì trình biên dịch thấy hằng số đúng trong trường hợp và tối ưu hóa điều kiện. Tôi không thực sự hiểu tại sao điều này sẽ "sửa" ví dụ đầu tiên.

Oh, và thậm chí nhiều hơn thật là thú vị, nếu một số tối ưu hóa mà được thoát khỏi vòng lặp là trong vở kịch, đây biên dịch:

private int Example3() 
    { 
     while (true) 
     { 
      if (false) 
      { 
       return 1; 
      } 
     } 
    } 

tôi sẽ nghĩ rằng toàn bộ vòng lặp bên trong sẽ được tối ưu hóa đi, được thoát khỏi tất cả các lợi nhuận hợp lệ. Điều gì thực sự xảy ra ở đây ở cấp độ bytecode/trình biên dịch mà làm cho tất cả điều này có ý nghĩa?

+1

Tôi nghĩ ví dụ cuối cùng là trường hợp trình biên dịch nói * "Tôi hy vọng họ biết họ đang làm gì ..... "* – ChaosPandion

+0

+1 chưa bao giờ nghĩ đến những tình huống này. – Arun

Trả lời

29

Trình biên dịch không gắn cờ điều này vì kết thúc phương thức là không thể truy cập. Đó không phải là vấn đề - nó chỉ là vấn đề nếu bạn có thể đến cuối phương thức (dấu ngoặc đóng) mà không trả về một giá trị.

Đây không phải là một vấn đề của trình biên dịch tối ưu hóa - đó là một trường hợp sau đây các định nghĩa cho reachability quy định trong spec.

Lưu ý rằng bạn không cần một tuyên bố trở lại tại tất cả ... mã này là vô ích, nhưng hoàn toàn hợp lệ:

public int EndlessLoop() 
{ 
    while (true) 
    { 
    } 
} 
+1

+1 để mang lại ánh sáng "khả năng tiếp cận"! – Arun

+2

Eric Lippert, một trong những nhà phát triển trình biên dịch, đã viết blog về khả năng truy cập nếu bạn tò mò: http://blogs.msdn.com/b/ericlippert/archive/tags/reachability/ –

3

Để cung cấp cho bạn một trường hợp sử dụng cho các loại vòng lặp vô hạn, hãy xem xét mã sau:

public int KeyboardChecker() 
{ 
    while (true) 
    { 
     if (KeyHasBeenPressed()) 
     { 
      HandleKeyPress(); 
     } 
    } 
} 

Sau đó, bạn chạy phương thức này một cách không đồng bộ khi nhập bàn phím (đây là kiểu bỏ phiếu, thường thích hợp hơn).

Bạn có thể tưởng tượng các chuỗi trả về mã trạng thái khi chúng được hoàn tất, vì vậy giá trị trả về của phương thức là int. Tuy nhiên, vì chuỗi cụ thể này sẽ không bao giờ kết thúc, nó không phải là một vấn đề ở tất cả mà phương thức không chứa bất kỳ câu lệnh trả về nào. Các nhà thiết kế C# biết về các trường hợp sử dụng này và đã thực hiện phương pháp pháp lý ở trên.

Lưu ý rằng vấn đề chung của việc tìm ra liệu một phương pháp cụ thể sẽ luôn trả về một giá trị là không thể xác định (tức là, không thể được giải quyết bởi bất kỳ chương trình máy tính nào). Do đó, trình biên dịch C# có thể khiếu nại về mã sẽ luôn trả về một giá trị (mặc dù nó sẽ không bao giờ chấp nhận các chương trình không):

public int DoWork() 
{ 
    // The compiler doesn't figure out this will always be true. 
    if (((int)Math.Sqrt(4)) == 2) 
    { 
     return 3; 
    } 
    // And therefore complains that not all code paths return a value for this method. 
}