2010-09-24 11 views
6

So che usare goto è qualcosa che la maggior parte della gente dice di evitare, tuttavia ho letto su vari punti che a volte è utile se hai bisogno di un codice semplice. Attualmente ho molto semplice programma che deve essere ripetuta se l'utente seleziona quindi:C# goto use - che altro usare qui?

static void Main() 
{ 
    Restart: 
    ... 

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

sta usando goto qui davvero così male? Non riesco a vedere altro modo su come ripetere il codice senza fare cicli ecc. Questo sembra essere un modo molto semplice e pulito. O mi sta sfuggendo qualcosa?

+6

Cosa c'è di sbagliato nei loop? – Joe

+0

Non c'è niente di sbagliato nei loop, stavo solo chiedendo. – Pietro

+9

Ad ogni modo, ora ci sono [altre cose di cui preoccuparsi] (http://xkcd.com/292/). * SCNR * – Bobby

risposta

20
string userchoice; 

do {     

    userchoice=Console.ReadLine(); 

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

invece scrivere qualcosa di simile qui di seguito.

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

Sì, utilizzare goto non è corretto perché rende il codice meno leggibile.

+0

Secondo il suo esempio, sembra che voglia fare un po 'di logica prima di Console.ReadLine, quindi questo non si comporterà esattamente come il suo codice corrente, poiché legge prima dalla console, quindi esegue la logica. –

+8

Se è il caso fare {...} mentre (Console.ReadLine() == "y") funzionerà. – Numenor

+0

concordato.Penso che sia il modo più pulito per farlo. Buona risposta! –

5

Ovviamente se il codice farà sempre la stessa cosa, è necessario aggiungere un ciclo. È molto meglio di goto.

Usa qualcosa come questo

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

che dovrebbe funzionare bene per voi.

+0

-, hai qualche errore logico qui: dovrebbe ciclo mentre l'utente non si input "y", che è sbagliato - dovrebbe ciclo while gli input dell'utente "y" –

+0

@Andreas: Grazie. Risolto adesso Goto mi sono messo in testa immagino;) –

+0

rimosso downvot come hai corretto la tua risposta! –

3

userei un do/while:

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

-, questo genererà un errore di compilazione a causa di problemi di portata ... –

+0

downvote rimosso, a causa della correzione del Halfdan ... btw: perché tutti i ragazzi usano ' ""' ... :) –

+0

@Andreas forse causa è più veloce da digitare quando si effettua una risposta veloce –

2

è possibile utilizzare una funzione ricorsiva per fare lo stesso senza loop:

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

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

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

Si potrebbe (in casi estremi) incorrere in problemi di "ricorsione troppo profonda", che non si hanno nella situazione del ciclo. –

+0

Certo, lo consiglio come sempre nel codice di produzione, aggiungendo un limite per evitare il problema del limite profondo della ricorsione. Inoltre, preferisco l'opzione di loop, tuttavia ha chiesto di fare lo stesso senza usare un loop. –

2

Utilizzando metodi invece di GOTO è più ampiamente accettati :

static void Main() 
{ 
    Restart(); 
} 

static void Restart() 
{ 
    ...code 

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

C# non ottimizza ancora per la ricorsione in coda (correggimi se ho torto), quindi questo aumenterebbe il tuo stack di chiamate. Probabilmente non è un problema se questo è controllato dall'utente (come nel tuo esempio), ma considera se esegui Restart() migliaia di volte. Stack Overflow, ciao? – Zano

+1

Non è difficile verificare se ildasm chiamata coda è implementata e controllare per http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.tailcall(VS.95).aspx –

+0

E' un punto interessante @Zano, ma 15000 interazioni utente sembrano un po 'improbabili (per un'app console). –

0

Personalmente non ho mai dovuto usare un goto, e come Øyvind Bråthen e Númenor hanno dichiarato il metodo loop è di gran lunga il modo migliore per eseguire questa operazione.

Tuttavia, v'è un caso che mi viene in mente in cui un goto sarebbe utile

come un interruttore “caduta attraverso” è illegale in C# (causa un errore di compilazione):

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

per farlo funzionare è possibile utilizzare un goto:

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

-, relazione alla domanda ?? –

+0

un motivo valido per utilizzare il goto. Ho dichiarato che il ciclo era un'opzione migliore e che mi ha anche fornito l'unico vero uso che posso immaginare per un goto. – jimplode

+1

dannazione ... leggi la domanda: 'Stai usando goto qui davvero così male? Non riesco a vedere altro modo su come ripetere il codice senza fare looping ecc. ... come fa la tua risposta a catturare i loop ?? quindi dovrebbe essere piuttosto un commento –

1

utilizzare un ciclo Do while per sostituire il vostro goto come la sua molto più leggibile.

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

C'è una soluzione di base mancante nelle risposte,

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

    ... 

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

La dichiarazione break è considerato meno strutturato di un puro po ', ma più strutturato di un (vero) goto. Dovrebbe essere usato con parsimonia, ma ha i suoi usi come con lo other-stop-condition

sta usando goto qui davvero così male?

Non in questo semplice programma. Ma se continui a utilizzare goto per sostituire i loop, se/allora ecc. Il tuo codice aumenterà di complessità molto più rapidamente del codice che evita lo goto.

+0

La tua sostituzione di un goto con una pausa che è solo un altro tipo di goto anche se meno offensivo;) –

+0

@ Monkey Bare: Giusto, ho dimenticato qualche commento. –

+0

Sono sicuro che lo sapevi. A volte le persone usano le frasi break, continue e return liberamente, ma poi si guardano in orrore da goto senza rendersi conto che quelle dichiarazioni di controllo del flusso possono essere altrettanto brutte di un goto. –

4

Utilizzare goto qui è davvero così brutto?

nel marzo 1968, Dijkstra inviato una lettera al Communications of the ACM che è stato pubblicato con il titolo Go To Statement Considered Harmful. È una lettura interessante e parte della tradizione dei programmatori.

L'argomento contro GOTO presentato in questa lettera ha a che fare con il modo in cui i programmatori costruiscono un modello mentale per tracciare l'avanzamento dell'esecuzione del codice. Dijkstra sostiene che un tale modello mentale è importante, perché il valore delle variabili è significativo solo in relazione al progresso dell'esecuzione. Ad esempio, quando il nostro programma conta il numero di volte in cui si verifica un evento, c'è sempre un momento intermedio in cui si sono verificati eventi N, ma la variabile che ne tiene traccia non è stata ancora incrementata ed è ancora a N-1.

Egli passa attraverso questi passaggi nel suo ragionamento contro GOTO:

  1. prima prendere in considerazione un linguaggio molto semplice senza procedure, loops o GOTO. In tale linguaggio, il programmatore può monitorare mentalmente l'esecuzione immaginando un puntatore di esecuzione che avanza dall'inizio del file fino alla fine. Un singolo indice (ovvero il numero di riga) è sufficiente per modellare l'avanzamento dell'esecuzione.

  2. Ora aggiungiamo procedure alla lingua. L'avanzamento dell'esecuzione non può più essere monitorato da un singolo indice, come potrebbe essere all'interno di una procedura. Dobbiamo anche tenere traccia da quale linea è stata chiamata la procedura. Inoltre, le procedure possono essere chiamate da altre procedure. Pertanto, modelliamo l'andamento dell'esecuzione come una sequenza di indici. (Nella vita reale, i programmatori chiamano tale sequenza "stack trace".)

  3. Ora aggiungiamo loop alla lingua. Per ogni riga nella nostra traccia di stack che si trova all'interno di un corpo del ciclo, è necessario aggiungere un altro tipo di indice per modellare l'avanzamento dell'esecuzione: il conteggio della ripetizione.

  4. Ora aggiungiamo GOTO. Dijkstra sostiene che con l'uso sfrenato di GOTO, la nostra capacità di tracciare i progressi di esecuzione ora si interrompe. Possiamo ancora tenere traccia dell'avanzamento dell'esecuzione con un "clock di esecuzione" dicendo "ora stiamo eseguendo la 152esima istruzione". Tuttavia, questo non è veramente utile per stabilire il contesto che è necessario per interpretare i valori delle variabili.

Finché usiamo solo istruzioni GOTO per costruire loop semplici, si può sostenere che la situazione è equivalente a punto (3), e non c'è nessun problema. Ma in quel caso puoi semplicemente usare i costrutti del ciclo. Meglio tenere GOTO fuori dal tuo codice, in modo da non scivolare nella situazione descritta al punto (4).

+3

Vorrei aggiungere che i gotos sono spesso considerati accettabili nel codice auto-generato dalla macchina generata. In effetti, per le statemachines generate automaticamente possono essere l'unica opzione sensata. –