Quando você precisa repetir um leitor em que o número de itens a ler é desconhecido, e a única maneira de fazer isso é continuar lendo até chegar ao fim.
Geralmente, é o lugar em que você precisa de um loop sem fim.
Há sempre o
true
que indica que deve haver uma declaraçãobreak
ou em algum lugar dentro do bloco.return
int offset = 0; while(true) { Record r = Read(offset); if(r == null) { break; } // do work offset++; }
Existe o método de leitura dupla para loop.
Record r = Read(0); for(int offset = 0; r != null; offset++) { r = Read(offset); if(r != null) { // do work } }
Existe o único loop while de leitura. Nem todos os idiomas suportam esse método .
int offset = 0; Record r = null; while((r = Read(++offset)) != null) { // do work }
Eu estou querendo saber qual abordagem é a menos provável de introduzir um bug, mais legível e comumente usada.
Toda vez que tenho que escrever um desses, penso que "deve haver uma maneira melhor" .
c#
code-quality
readability
Reactgular
fonte
fonte
Respostas:
Eu daria um passo para trás aqui. Você está se concentrando nos detalhes exigentes do código, mas está perdendo a imagem maior. Vamos dar uma olhada em um dos seus exemplos de loops:
Qual é o significado desse código? O significado é "faça algum trabalho para cada registro em um arquivo". Mas não é assim que o código se parece . O código parece "manter um deslocamento. Abra um arquivo. Insira um loop sem condição final. Leia um registro. Teste a nulidade". Tudo isso antes de começarmos o trabalho! A pergunta que você deve fazer é " como posso fazer a aparência desse código corresponder à sua semântica? " Esse código deve ser:
Agora o código parece com a sua intenção. Separe seus mecanismos da sua semântica . No seu código original, você mistura o mecanismo - os detalhes do loop - com a semântica - o trabalho realizado em cada registro.
Agora temos que implementar
RecordsFromFile()
. Qual é a melhor maneira de implementar isso? Quem se importa? Esse não é o código que alguém vai ver. É o código básico do mecanismo e suas dez linhas. Escreva como quiser. Que tal agora?Agora que estamos manipulando uma sequência de registros lenta e computada, todos os tipos de cenários se tornam possíveis:
E assim por diante.
Sempre que você escreve um loop, pergunte a si mesmo "esse loop é como um mecanismo ou como o significado do código?" Se a resposta for "como um mecanismo", tente mover esse mecanismo para seu próprio método e escreva o código para tornar o significado mais visível.
fonte
Você não precisa de um loop sem fim. Você nunca deve precisar de um em cenários de leitura de C #. Esta é minha abordagem preferida, supondo que você realmente precise manter um deslocamento:
Essa abordagem reconhece o fato de que há uma etapa de configuração para o leitor, portanto, há duas chamadas de método de leitura. A
while
condição está no topo do loop, apenas no caso de não haver dados no leitor.fonte
Bem, isso depende da sua situação. Mas uma das soluções "c # -ish" em que consigo pensar é usar a interface IEnumerable interna e um loop foreach. A interface do IEnumerator apenas chama MoveNext com true ou false, portanto o tamanho pode ser desconhecido. Então sua lógica de terminação é escrita uma vez - no enumerador - e você não precisa repetir em mais de um ponto.
O MSDN fornece um exemplo de IEnumerator <T> . Você também precisará criar um IEnumerable <T> para retornar o IEnumerator <T>.
fonte
Quando tenho operações de inicialização, condição e incremento, gosto de usar loops de linguagens como C, C ++ e C #. Como isso:
Ou isso, se você acha que isso é mais legível. Eu pessoalmente prefiro o primeiro.
fonte