Có ai vẫn sử dụng [goto] trong C # không và nếu có thì tại sao? [đóng cửa]


104

Tôi đã tự hỏi liệu có ai vẫn sử dụng cú pháp từ khóa "goto" trong C # hay không và những lý do có thể có để làm như vậy.

Tôi có xu hướng xem bất kỳ câu lệnh nào khiến người đọc phải nhảy xung quanh mã là hành vi xấu nhưng tự hỏi liệu có bất kỳ tình huống đáng tin cậy nào cho việc sử dụng một cú pháp như vậy không?

Goto Định nghĩa Từ khoá


3
ý bạn là "vẫn"? Đã có khoảng thời gian nào mọi người sử dụng nó mọi lúc [trong c #] không?
Massif

4
@Massif: "vẫn" nhằm mục đích nhấn mạnh quan điểm hiện đại về việc sử dụng "goto" như một phần mở đầu cho mã spaghetti và sự thiếu khả năng đọc trong mã nguồn. Rất hiếm khi bạn thấy bất kỳ ví dụ mã nào bao gồm từ khóa cụ thể này, đó là lý do tại sao tôi quan tâm đến việc hỏi ngay từ đầu.
Brian Scott

50
Nếu người đọc "nhảy xung quanh" mã là thực hành xấu thì bạn cũng tránh được "break", "continue", "throw" và "return"? Tất cả chúng đều gây ra một nhánh trong luồng điều khiển, đôi khi là một nhánh không cục bộ. "Throw" thậm chí không cho bạn biết nó sẽ đi đâu, không giống như goto.
Eric Lippert

2
Tôi sử dụng gotođể phá vỡ một vòng lặp và quay trở lại bắt đầu tuyên bố theo điều kiện cụ thể
Nitin Sawant

3
Tôi thích goto. Tôi đã cố gắng tránh nó vì xu hướng mọi người nói tránh nó vì nó làm cho mã khó đọc hơn. Sau khi học ngôn ngữ Assembly và các câu lệnh rẽ nhánh, tôi nghĩ rằng đôi khi, nó có thể làm cho mã dễ đọc hơn. Tôi nghĩ rằng sử dụng nhiều lần trong một phương pháp và nhảy quá xa trong mã có thể gây hại nhiều hơn lợi. Nhưng nếu bạn đang nghĩ một goto sẽ hoạt động tốt ở đây, thì một goto đơn giản thỉnh thoảng sẽ không khiến bạn phải trốn tránh chỉ vì sự đồng thuận chung là tránh nó.
Eaglei22

Câu trả lời:


93

Có một số (hiếm) trường hợp goto thực sự có thể cải thiện khả năng đọc. Trên thực tế, tài liệu bạn liên kết đến liệt kê hai ví dụ:

Cách sử dụng phổ biến của goto là chuyển quyền điều khiển sang nhãn trường hợp chuyển mạch cụ thể hoặc nhãn mặc định trong câu lệnh chuyển đổi.

Câu lệnh goto cũng hữu ích để thoát ra khỏi các vòng lặp lồng nhau sâu.

Đây là một ví dụ cho cái sau:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

Tất nhiên, có những cách khác để giải quyết vấn đề này, chẳng hạn như cấu trúc lại mã thành một hàm, sử dụng một khối giả xung quanh nó, v.v. (xem câu hỏi này để biết chi tiết). Lưu ý thêm, các nhà thiết kế ngôn ngữ Java đã quyết định cấm goto hoàn toàn và thay vào đó giới thiệu một câu lệnh break có nhãn .


47
Thông thường tôi sẽ cố gắng để cấu trúc lại này để đặt các vòng trong một phương pháp riêng biệt mà tôi chỉ có thể trở về từ ...
Jon Skeet

2
@Heinzi - Tôi chưa thấy goto được bảo hành. Giống như Jon nói, nếu nó đang được "bảo hành", thì mã sẽ được cấu trúc lại.
manojlds

29
được gắn nhãn break, chỉ là một cách nói dài hơn của goto bởi vì nó làm điều kỳ cục tương tự ....
Jesus Ramos

20
@Jesus nhưng sau đó với goto, bạn có thể đi bất cứ đâu. Dấu ngắt được gắn nhãn đảm bảo bạn đang đi ngay bên ngoài vòng lặp.
mihsathe

1
Trừ khi bạn đang mạo hiểm và sử dụng goto với một địa chỉ (tôi đã thấy nó trước đây) thì vấn đề đó sẽ được giảm thiểu. Và tôi nghi ngờ ai đó đang sử dụng các móc vòng trong mã C # và Java của bạn để khai thác các câu lệnh goto.
Jesus Ramos

65

Tôi nhớ phần này

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

Để một cái gì đó như thế này

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

Tham khảo này


17
Tôi thực sự thấy đây là lý do hợp lệ nhất để sử dụng [goto]. Ít nhất trong trường hợp này, nó tăng khả năng đọc cho các lập trình viên không biết rằng các trường hợp rơi vào nhau mà không có câu lệnh break.
Brian Scott

11
@Brian Scott, V4Vendetta. Trừ khi tôi nhầm, câu lệnh đầu tiên không được biên dịch trong C #. Điều đó sẽ giúp lập trình viên hiểu được.
Jodrell

2
V4Vendetta tại sao bạn lại chèn dấu ngắt trên đoạn mã đầu tiên ...? Tốt hơn là nên hiển thị nó mà không có thời gian nghỉ, nếu không hai đoạn trích làm những việc khác nhau. Lý do tại sao bạn cần goto trong ví dụ thứ hai chính là vì cái đầu tiên không biên dịch trong C # (như trong C).
Stephen Holt

23

Tôi sử dụng nó rộng rãi trong Eduasync để hiển thị loại mã mà trình biên dịch tạo ra cho bạn khi sử dụng các phương thức không đồng bộ trong C # 5. Bạn sẽ thấy điều tương tự trong các khối trình lặp.

Tuy nhiên, trong mã "bình thường", tôi không thể nhớ lần cuối cùng tôi sử dụng nó ...


1
bạn có thể cung cấp một ví dụ nhỏ về lý do tại sao cách tiếp cận này được ưa thích hay chỉ đơn giản là sở thích cá nhân?
Brian Scott

1
@Brian: Không rõ ý bạn lắm. Eduasync cho thấy mã C tương đương # với những gì trình biên dịch làm cho bạn - và nó tạo ra mã mà sử dụng goto, hiệu quả ...
Jon Skeet

9

goto là tuyệt vời để thoát ra khỏi nhiều vòng lặp mà break sẽ không hoạt động tốt (giả sử khi có điều kiện lỗi), và như Kragen đã nói goto được trình biên dịch sử dụng để tạo các câu lệnh switch và một số thứ khác.


7
Chắc chắn "break" / "continue" là cách tiếp cận tốt hơn để quản lý vòng lặp hơn là yêu cầu trình soạn thảo mã nhảy xung quanh mã nguồn cố gắng hiểu nơi xảy ra bước tiếp theo?
Brian Scott

6
Không nếu bạn có các vòng lặp lồng nhau.
Jesus Ramos

1
ok, tôi có thể xem đây là một kịch bản hợp lệ.
Brian Scott

1
Trong một điều kiện lỗi, bạn nên xem xét việc ném một ngoại lệ.
Jodrell

6
Nếu bạn muốn xử lý lỗi nội bộ mà không có ngoại lệ, đây sẽ là một cách hợp lệ để làm như vậy.
Jesus Ramos

8

Tôi không nhớ đã từng sử dụng goto. Nhưng có thể nó cải thiện mục đích của một vòng lặp mãi mãi mà bạn thực sự không bao giờ muốn thoát ra (không break, nhưng bạn vẫn có thể returnhoặc throw):

forever: {
  // ...
  goto forever;
}

Sau đó, một lần nữa, đơn giản là while (true)đủ ...

Ngoài ra, bạn có thể sử dụng trong trường hợp bạn muốn lần lặp đầu tiên của vòng lặp bắt đầu ở giữa vòng lặp: hãy xem ví dụ ở đây .


Các câu trả lời liên quan chứa một sử dụng "thú vị" của goto.. và while(true) {..}không phải là một sử dụng thú vị ..
user2864740

5

Trình biên dịch sử dụng các gotocâu lệnh trong các đoạn mã được tạo khác nhau, ví dụ như trong các loại khối trình vòng lặp được tạo (được tạo khi sử dụng yield returntừ khóa - tôi khá chắc chắn rằng các loại tuần tự hóa XML được tạo cũng có một vài gotocâu lệnh ở đâu đó.

Xem chi tiết triển khai khối Iterator: máy trạng thái được tạo tự động để biết thêm chi tiết về lý do / cách trình biên dịch C # xử lý điều này.

Ngoài mã được tạo ra, không có lý do chính đáng để sử dụng một gotocâu lệnh trong mã bình thường - nó làm cho mã khó hiểu hơn và kết quả là dễ xảy ra lỗi hơn. Mặt khác, việc sử dụng các gotocâu lệnh trong mã được tạo như thế này có thể đơn giản hóa quá trình tạo và thông thường sẽ ổn vì không ai đọc (hoặc sửa đổi) mã được tạo và không có khả năng mắc lỗi do máy đang thực hiện việc ghi.

Xem Câu lệnh Go-to được coi là có hại cho một lập luận chống lại gotocũng như một phần lịch sử lập trình cổ điển.


4
Điều này thật ngu ngốc: có một số trường hợp goto là hữu ích, như được minh họa bằng các câu trả lời khác. Hoặc bạn bôi nhọ chúng một cách rõ ràng, hoặc chỉ nói "nó sai" là sai.
o0 '.

@Lohoris Tôi không mua nó - mỗi ví dụ tôi đã nhìn thấy nơi goto "cải thiện khả năng đọc" (bao gồm cả các câu trả lời ở đây) sẽ được xa hơn có thể đọc được sau khi một số refactoring đơn giản.
Justin

3
@Justin không, đôi khi các vòng lặp lồng nhau chỉ là cách tự nhiên nhất để thực hiện một việc gì đó, chẳng hạn như nếu bạn đang duyệt một mảng các mảng.
o0 '.

6
@Justin không phải lúc nào cũng rõ ràng hơn khi đưa nó vào một chức năng. Bạn đang buộc một thứ gì đó (có chức năng) chỉ để tránh thứ mà bạn ghét về mặt tôn giáo (sử dụng goto). Dấu hiệu rõ ràng về việc làm sai.
o0 '.

3
@Justin Functions gọi có phí. gotokhông làm. Một cái gì đó để xem xét.
Dan Bechard

2

Bộ xử lý thực hiện ít nhất một lệnh nhảy và tôi chắc chắn rằng rất nhiều câu lệnh sử dụng những lệnh đó trong quá trình triển khai hoặc diễn giải của chúng.

Một trong những điều tốt khi sử dụng langauge thế hệ thứ 3 hoặc thứ 4 là những chi tiết vật lý này không còn xa chúng ta nữa. Trong khi chúng ta nên lưu tâm đến quy luật trừu tượng bị rò rỉ, tôi nghĩ rằng chúng ta cũng nên sử dụng các công cụ của mình như dự định của chúng ( xin lỗi ). Nếu tôi đang viết mã và đó gotocó vẻ là một ý tưởng hay, thì đã đến lúc cấu trúc lại. Mục đích của ngôn ngữ có cấu trúc là để tránh những "bước nhảy" này và tạo ra một luồng logic trong kỹ thuật của chúng ta.

Tôi nên tránh việc sử dụng breaknhưng tôi không thể bỏ qua lợi ích hiệu suất. Tuy nhiên, nếu tôi có các vòng lặp lồng nhau cùng cần thì đã đến breaklúc cấu trúc lại.

Nếu ai đó có thể đề xuất việc sử dụng gotođiều đó có vẻ tốt hơn việc tái cấu trúc, tôi sẽ sẵn lòng rút lại câu trả lời của mình.

Tôi hy vọng mình không có tội khi lao vào "bãi xe đạp " ở đây. Như Kragen nói, những gì đủ tốt cho Dijkstra cũng đủ tốt cho tôi.


1
Lấy một dynamicđối tượng và di chuyển biểu đồ đối tượng của nó có chứa nhiều từ điển để đưa ra các giá trị tôi cần. Không hợp lý khi sử dụng các phương thức có tham số dynamicnhưng vẫn mong đợi một hình dạng đối tượng chính xác. Với goto để chia ra nhiều lớp và tiếp tục đi qua bộ sưu tập các đối tượng này. [Tôi không sở hữu các loại vì vậy tôi không thể cung cấp truy cập tốt hơn, để phản ánh hoặc động đó là]
Chris Marisic

-6

Goto không bao giờ tốt hơn. Và tiếp tục, break (trừ trường hợp switch / case), (nhiều) trả lại và ném cũng nên được giữ ở mức tối thiểu nhất. Bạn không bao giờ muốn thoát khỏi giữa các vòng lặp của tổ. Bạn luôn muốn các câu lệnh điều khiển vòng lặp có tất cả các điều khiển vòng lặp. Thụt lề có thông tin, và tất cả những tuyên bố này đều loại bỏ thông tin đó. Bạn cũng có thể loại bỏ tất cả các thụt lề.


10
Bạn sẽ muốn thoát ra khỏi vòng lặp nếu không có ý nghĩa gì trong việc duy trì việc thực hiện vòng lặp. Nếu không, bạn sẽ lãng phí nhiều thời gian xử lý hơn trong các vòng dài hơn mà không có lý do.
Skuld

12
@Kirk, điều này nghe giống như một ý kiến ​​hơn là bất cứ điều gì mang tính định lượng?
Brian Scott
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.