Alguém ainda usa em c # e se sim por quê?

Eu queria saber se alguém ainda usa a syntax de palavra-chave “goto” em c # e quais as possíveis razões para fazê-lo.

Eu tenho a tendência de ver qualquer declaração que faça o leitor pular o código como uma má prática, mas imagino se há algum cenário confiável para usar tal syntax?

Definição de palavras-chave de ir para

Existem alguns casos (raros) em que o goto pode realmente melhorar a legibilidade. Na verdade, a documentação que você vinculou lista dois exemplos:

Um uso comum do goto é transferir o controle para um label específico de caso de comutador ou o label padrão em uma instrução switch.

A instrução goto também é útil para sair de loops profundamente nesteds.

Aqui está um exemplo para o último:

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

Naturalmente, há outras maneiras de contornar esse problema também, como refatorar o código em uma function, usar um bloco fictício ao redor dele, etc. (veja esta questão para detalhes). Como uma nota lateral, os projetistas da linguagem Java decidiram banir completamente e introduzir uma instrução de quebra rotulada .

Eu lembro dessa parte

 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; } 

Para algo assim

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

Referir isto

Eu uso-o extensivamente em Eduasync para mostrar o tipo de código que o compilador gera para você ao usar methods asynchronouss em C # 5. Você veria a mesma coisa em blocos de iteradores.

No código “normal”, não lembro da última vez que usei …

goto é ótimo para quebrar muitos loops onde break não funcionaria bem (digamos, sob condições de erro), e como Kragen disse, goto é usado pelo compilador para gerar instruções de switch e algumas outras coisas também.

O compilador usa instruções goto em várias partes do código gerado, por exemplo, em tipos de blocos de iteradores gerados (gerados ao usar a palavra-chave yield return – tenho certeza que os tipos de serialização XML gerados também possuem algumas instruções goto em algum lugar também.

Consulte Detalhes da implementação do bloco Iterator: máquinas de estado geradas automaticamente para mais detalhes sobre por que / como o compilador C # manipula isso.

Além do código gerado, não há uma boa razão para usar uma instrução goto no código normal – isso torna o código mais difícil de entender e, como resultado, mais propenso a erros. Por outro lado, usar instruções goto em código gerado como este pode simplificar o processo de geração e normalmente é bom porque ninguém vai ler (ou modificar) o código gerado e não há chance de erros sendo cometidos porque uma máquina está fazendo a escrita .

Veja a declaração Go-to considerada prejudicial para um argumento contra o goto , bem como uma peça clássica da história da programação.

Não me lembro de usar goto . Mas talvez isso melhore a intenção de um loop permanente que você realmente nunca quer sair (sem break , mas você ainda pode return ou throw ):

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

Então, novamente, um simples while (true) deve ser suficiente …

Além disso, você poderia usar em uma situação onde deseja que a primeira iteração de um loop inicie no meio do loop: procure aqui um exemplo.

O processador implementa pelo menos uma instrução de salto e tenho certeza de que muitas declarações usam essas em sua implementação ou interpretação.

Uma das coisas boas sobre o uso de uma linguagem de terceira ou quarta geração é que esses detalhes físicos são abstraídos de nós. Embora devamos estar cientes da lei da abstração permeável , acho que devemos também usar nossas ferramentas como elas são intencionadas ( desculpe ). Se eu estivesse escrevendo código e um goto parecesse uma boa ideia, seria hora de refatorar. O propósito de uma linguagem estruturada é evitar esses “saltos” e criar um stream lógico em nossa engenharia.

Devo evitar o uso de break mas não posso ignorar o benefício de desempenho. No entanto, se eu tiver nested loops que mutuamente precisam break , é hora de refatorar.

Se alguém puder propor um uso de goto que pareça melhor do que refatorar, terei prazer em retirar minha resposta.

Espero não ser culpado de correr para o ” galpão das bicicletas ” aqui. Como Kragen diz, o que é bom o suficiente para Dijkstra é bom o suficiente para mim.

Eu estava olhando para o código-fonte .net e corri para isso na propriedade ControlStyle para um WebControl

 public Style ControlStyle { get { if (this.controlStyle == null) { this.controlStyle = this.CreateControlStyle(); if (base.IsTrackingViewState) { this.controlStyle.TrackViewState(); } if (!this._webControlFlags[1]) { goto IL_4D; } this._webControlFlags.Clear(1); this.controlStyle.LoadViewState(null); } IL_4D: return this.controlStyle; } } 

Então, até a Microsoft usa

É particularmente bom quando você precisa limpar antes de retornar de um método, por exemplo.

  while (stream.Read(buffer, 0, 4) == 4) { // do smth with the 4 bytes read here if (stream.Read(buffer, 0, 4) != 4) goto CLOSE_STREAM_AND_RETURN; // do more stuff if (stream.Read(buffer, 0, 4) != 4) goto CLOSE_STREAM_AND_RETURN; // more stuff } CLOSE_STREAM_AND_RETURN: stream.Close(); 

Inspirado por: http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

Goto nunca é melhor. E continue, quebre (exceto em switch / case), (multiple) return, e throw também deve ser mantido no mínimo. Você nunca quer escaping do meio dos loops de ninho. Você sempre quer que as instruções de controle de loop tenham todo o controle de loop. Recuo tem informação, e todas essas declarações jogam fora essa informação. Você também pode tirar todo o recuo.