2010-09-24 19 views
6

Tôi biết sử dụng goto là điều mà hầu hết mọi người nói để tránh, tuy nhiên tôi đã đọc ở những nơi khác nhau mà đôi khi nó hữu ích nếu bạn cần mã đơn giản. Hiện nay tôi có chương trình rất đơn giản mà cần phải được lặp lại nếu người dùng chọn như vậy:C# goto sử dụng - còn gì khác để sử dụng ở đây?

static void Main() 
{ 
    Restart: 
    ... 

    string UserChoice=Console.ReadLine(); 
    if (UserChoice=="y") 
    goto Restart; 
} 

Đang sử dụng goto đây thực sự xấu như vậy? Tôi chỉ không thể nhìn thấy bất kỳ cách nào khác làm thế nào để lặp lại mã mà không làm vòng vv Điều này có vẻ là rất đơn giản và sạch sẽ. Hay tôi đang thiếu một cái gì đó?

+6

Có gì sai với vòng lặp? – Joe

+0

Không có gì sai với vòng lặp, tôi chỉ hỏi. – Pietro

+9

Dù sao, bây giờ bạn có [những thứ khác phải lo lắng] (http://xkcd.com/292/). * SCNR * – Bobby

Trả lời

20
string userchoice; 

do {     

    userchoice=Console.ReadLine(); 

} while (userchoice=="y"); 
5

thay vì viết một cái gì đó như dưới đây.

while(Console.ReadLine() == "y") 
{ 
..... 
} 

Có sử dụng goto là xấu bởi vì nó làm cho mã của bạn ít có thể đọc được.

+0

Theo ví dụ của anh ta, có vẻ như anh ta muốn làm một số logic trước Console.ReadLine, vì vậy điều này sẽ không hoạt động chính xác như mã hiện tại của anh ta, vì nó đọc từ bảng điều khiển trước, sau đó thực hiện logic. –

+8

Nếu trường hợp đó xảy ra {...} trong khi (Console.ReadLine() == "y") sẽ hoạt động. – Numenor

+0

Đồng ý.Tôi nghĩ đó là cách làm sạch nhất. Câu trả lời tốt! –

5

Tất nhiên nếu mã của bạn sẽ làm điều tương tự lặp đi lặp lại, bạn phải thêm một vòng lặp. Đó là tốt hơn nhiều so với goto.

Sử dụng một cái gì đó như thế này

string UserChoice = "y"; 
while(UserChoice == "y"){ 
    ... 
    UserChoice=Console.ReadLine(); 
} 

Điều đó sẽ làm việc diễn ra tốt đẹp cho bạn.

+0

-, bạn có một số sai lầm hợp lý ở đây: nó sẽ lặp trong khi người dùng không nhập "y" sai - nó sẽ lặp trong khi người dùng nhập "y" –

+0

@Andreas: Cảm ơn. Sửa lỗi ngay bây giờ. Goto đã đến đầu của tôi tôi đoán;) –

+0

loại bỏ downvote như bạn đã sửa chữa câu trả lời của bạn! –

3

Tôi muốn sử dụng một việc phải làm/Vòng lặp while:

string UserChoice = ""; 
do { 
    ... 
    UserChoice=Console.ReadLine(); 
} while(UserChoice == "y"); 
+2

-, điều này sẽ tạo ra lỗi biên dịch do các vấn đề về phạm vi ... –

+0

xóa bỏ ghi đè, do chỉnh sửa nửadan ... btw: tại sao tất cả các kẻ sử dụng '" "' ... :) –

+0

@Andreas có thể gây ra của nó nhanh hơn để gõ khi thực hiện một câu trả lời nhanh –

2

Bạn có thể sử dụng một hàm đệ quy để làm như vậy mà không có vòng:

public static void Main(string[] args) 
{ 
    PrintChoices(); 
} 

private static void PrintChoices() 
{ 
    string userChoice = Console.ReadLine(); 

    if (userChoice == "y") 
     PrintChoices();   
} 
+2

Bạn có thể (trong trường hợp cực đoan) chạy vào "đệ quy quá sâu" vấn đề, mà bạn không có trong tình hình vòng lặp. –

+0

Chắc chắn, tôi khuyên bạn nên luôn luôn trong mã sản xuất, thêm một giới hạn để tránh các vấn đề giới hạn đệ quy sâu. Ngoài ra, tôi prefere tùy chọn looping tuy nhiên ông yêu cầu làm như vậy mà không cần sử dụng một vòng lặp. –

2

Sử dụng phương pháp thay vì gotos được chấp nhận rộng rãi hơn :

static void Main() 
{ 
    Restart(); 
} 

static void Restart() 
{ 
    ...code 

    string userChoice = Console.ReadLine(); 
    if (userChoice=="y") 
     Restart(); 
} 
+1

C# chưa tối ưu hóa cho đệ quy đuôi (đúng với tôi nếu tôi sai), vì vậy điều này sẽ phát triển ngăn xếp cuộc gọi của bạn. Có lẽ không phải là một vấn đề nếu điều này được người dùng kiểm soát (như trong ví dụ của bạn), nhưng hãy xem xét nếu bạn chạy Restart() hàng ngàn lần. Stack Overflow, xin chào? – Zano

+1

Không khó để kiểm tra xem cuộc gọi đuôi có được triển khai ildasm hay không và kiểm tra http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.tailcall(VS.95).aspx –

+0

Đó là một Điểm thú vị @Zano, nhưng 15.000 tương tác của người dùng có vẻ hơi khó (đối với ứng dụng giao diện điều khiển). –

0

Cá nhân tôi chưa bao giờ phải sử dụng goto và giống như Bråthen và Numenor đã nêu phương pháp vòng lặp là cách tốt nhất để thực hiện tác vụ này.

Tuy nhiên, có một trường hợp mà tôi có thể nghĩ ra nơi một goto sẽ là hữu ích

Là một công tắc “mùa thu đến” là bất hợp pháp trong C# (gây ra một lỗi biên dịch):

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

Để ứng dụng hoạt động, bạn có thể sử dụng goto:

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

-, liên quan đến câu hỏi? –

+0

lý do hợp lệ để sử dụng goto. Tôi đã nói rằng vòng lặp là một lựa chọn tốt hơn và cũng cung cấp chỉ sử dụng thực tế tôi có thể nghĩ đến cho một goto. – jimplode

+1

damn ... đọc câu hỏi: 'Sử dụng goto ở đây thực sự quá tệ? Tôi chỉ không thể nhìn thấy bất kỳ cách nào khác làm thế nào để lặp lại mã mà không làm vòng vv ... ... làm thế nào để câu trả lời của bạn chụp vòng ?? do đó, nó nên được một bình luận –

1

Sử dụng vòng lặp trong khi thay thế goto của bạn càng dễ đọc hơn.

do 
{ 
... 
} 
while(Console.ReadLine() == "y"); 
2

Có một giải pháp cơ bản còn thiếu trong các câu trả lời,

while (true) 
{ 
    ... 
    if (other-stop-condition) break;  

    ... 

    string UserChoice=Console.ReadLine(); 
    if (UserChoice != "y") break; 
} 

Tuyên bố break được coi là ít có cấu trúc hơn là một tinh khiết trong khi nhưng nhiều cấu trúc hơn một (thực) goto. Nó nên được sử dụng một cách tiết kiệm, nhưng nó có cách sử dụng giống như với các số

đang sử dụng goto ở đây thực sự quá tệ?

Không có trong chương trình đơn giản này. Nhưng nếu bạn tiếp tục sử dụng goto để thay thế vòng lặp, nếu/thì vv mã của bạn sẽ tăng độ phức tạp nhanh hơn nhiều so với mã tránh goto.

+0

Thay thế một goto của bạn với một break mà chỉ là một loại goto mặc dù ít tấn công;) –

+0

@Bear Monkey: Phải, tôi quên một số bình luận. –

+0

Chắc chắn bạn biết điều đó. Đôi khi mọi người sử dụng break, tiếp tục và trả lại các câu lệnh một cách tự do nhưng sau đó nhảy vào kinh dị tại gotos mà không nhận ra rằng dòng chảy của các câu lệnh kiểm soát đó có thể xấu như một goto. –

4

Sử dụng goto ở đây thực sự quá tệ?

Vào tháng Ba năm 1968, Dijkstra gửi một bức thư cho Communications of the ACM được xuất bản dưới tiêu đề Go To Statement Considered Harmful. Đây là một bài đọc thú vị và là một phần của truyền thuyết lập trình.

Đối số chống lại GOTO được trình bày trong thư này phải liên quan đến cách lập trình viên xây dựng mô hình tinh thần để theo dõi tiến trình thực thi mã. Dijkstra lập luận rằng một mô hình tâm thần như vậy là quan trọng, bởi vì giá trị của các biến chỉ có ý nghĩa liên quan đến tiến trình thực hiện. Ví dụ, khi chương trình của chúng ta đếm số lần một sự kiện xảy ra, luôn luôn có một khoảnh khắc ở giữa mà N sự kiện đã xảy ra, nhưng biến theo dõi của nó vẫn chưa được tăng lên và vẫn ở N-1.

Ông đi qua các bước trong lập luận của mình chống lại GOTO:

  1. Đầu tiên xem xét một ngôn ngữ rất đơn giản mà không cần thủ tục, cáp bẹ hoặc GOTO. Trong một ngôn ngữ như vậy, lập trình viên có thể theo dõi tinh thần thực hiện bằng cách tưởng tượng một con trỏ thực hiện tiến từ đầu tệp đến cuối. Một chỉ mục duy nhất (tức là số dòng) đủ để mô hình tiến trình thực hiện.

  2. Bây giờ, chúng tôi thêm thủ tục vào ngôn ngữ. Tiến trình thực hiện có thể không còn được theo dõi bởi một chỉ mục duy nhất, vì nó có thể nằm trong một thủ tục. Chúng tôi cũng phải theo dõi từ đó thủ tục được gọi. Ngoài ra, thủ tục có thể được gọi từ các thủ tục khác. Do đó, chúng tôi lập mô hình tiến trình thực hiện như một chuỗi các chỉ mục. (Trong cuộc sống thực, các lập trình viên gọi một chuỗi như vậy là "dấu vết ngăn xếp".)

  3. Bây giờ chúng ta thêm các vòng vào ngôn ngữ. Đối với mỗi dòng trong dấu vết ngăn xếp của chúng ta nằm bên trong một vòng lặp, chúng ta cần phải thêm một loại chỉ mục khác để mô hình tiến trình thực hiện: số đếm lặp lại.

  4. Bây giờ chúng tôi thêm GOTO. Dijkstra lập luận rằng với việc sử dụng GOTO không hạn chế, khả năng theo dõi tiến độ thực hiện của chúng tôi hiện nay bị hỏng. Chúng tôi vẫn có thể theo dõi tiến độ thực hiện với "đồng hồ thực hiện" bằng cách nói "bây giờ chúng tôi đang thực hiện câu lệnh 152". Tuy nhiên, điều này không thực sự hữu ích khi thiết lập ngữ cảnh cần thiết để diễn giải các giá trị của các biến.

Miễn là chúng tôi chỉ sử dụng câu lệnh GOTO để xây dựng vòng lặp đơn giản, bạn có thể cho rằng tình huống tương đương với điểm (3) và không có vấn đề gì. Nhưng trong trường hợp đó bạn chỉ có thể sử dụng các cấu trúc vòng lặp. Tốt hơn là chỉ giữ GOTO ra khỏi mã của bạn, để bạn không rơi vào tình huống được mô tả tại điểm (4).

+3

Tôi sẽ thêm rằng gotos thường được coi là chấp nhận được trong mã được tiêu thụ tự động do máy tạo ra. Thực tế cho các statemachines được tạo tự động, chúng có thể là lựa chọn hợp lý duy nhất. –

Các vấn đề liên quan