Cuando tiene que iterar un lector donde se desconoce el número de elementos para leer, y la única forma de hacerlo es seguir leyendo hasta llegar al final.
Este es a menudo el lugar donde necesita un bucle sin fin.
Siempre existe el
true
que indica que debe haber una declaraciónbreak
o en algún lugar dentro del bloque.return
int offset = 0; while(true) { Record r = Read(offset); if(r == null) { break; } // do work offset++; }
Existe el método de doble lectura para bucle.
Record r = Read(0); for(int offset = 0; r != null; offset++) { r = Read(offset); if(r != null) { // do work } }
Hay una sola lectura mientras que el bucle. No todos los idiomas admiten este método .
int offset = 0; Record r = null; while((r = Read(++offset)) != null) { // do work }
Me pregunto qué enfoque es el menos probable para introducir un error, el más legible y el más utilizado.
Cada vez que tengo que escribir uno de estos pienso "tiene que haber una mejor manera" .
c#
code-quality
readability
Reactgular
fuente
fuente
Respuestas:
Daría un paso atrás aquí. Te estás concentrando en los detalles exigentes del código pero te falta la imagen más grande. Echemos un vistazo a uno de sus bucles de ejemplo:
¿Cuál es el significado de este código? El significado es "hacer un trabajo para cada registro en un archivo". Pero ese no es el aspecto del código . El código se ve como "mantener un desplazamiento. Abra un archivo. Ingrese un bucle sin condición final. Lea un registro. Pruebe la nulidad". ¡Todo eso antes de llegar al trabajo! La pregunta que debe hacerse es " ¿cómo puedo hacer que la apariencia de este código coincida con su semántica? " Este código debería ser:
Ahora el código se lee como su intención. Separe sus mecanismos de su semántica . En su código original, mezcla el mecanismo, los detalles del bucle, con la semántica, el trabajo realizado para cada registro.
Ahora tenemos que implementar
RecordsFromFile()
. ¿Cuál es la mejor manera de implementar eso? ¿A quien le importa? Ese no es el código que cualquiera va a mirar. Es un código de mecanismo básico y sus diez líneas de largo. Escríbela como quieras. ¿Qué tal esto?Ahora que estamos manipulando una secuencia de registros calculada de manera perezosa, es posible todo tipo de escenarios:
Y así.
Cada vez que escriba un bucle, pregúntese "¿este bucle se lee como un mecanismo o como el significado del código?" Si la respuesta es "como un mecanismo", intente mover ese mecanismo a su propio método y escriba el código para que el significado sea más visible.
fuente
No necesitas un bucle sin fin. Nunca debería necesitar uno en escenarios de lectura de C #. Este es mi enfoque preferido, suponiendo que realmente necesite mantener un desplazamiento:
Este enfoque reconoce el hecho de que hay un paso de configuración para el lector, por lo que hay dos llamadas al método de lectura. La
while
condición está en la parte superior del bucle, en caso de que no haya ningún dato en el lector.fuente
Bueno, depende de tu situación. Pero una de las soluciones más "C # -ish" que se me ocurre es usar la interfaz IEnumerable incorporada y un bucle foreach. La interfaz para IEnumerator solo llama a MoveNext con verdadero o falso, por lo que el tamaño puede ser desconocido. Luego, su lógica de terminación se escribe una vez, en el enumerador, y no tiene que repetir en más de un lugar.
MSDN proporciona un ejemplo de IEnumerator <T> . También deberá crear un IEnumerable <T> para devolver el IEnumerator <T>.
fuente
Cuando tengo operaciones de inicialización, condición e incremento, me gusta usar los bucles for de lenguajes como C, C ++ y C #. Me gusta esto:
O esto si crees que esto es más legible. Yo personalmente prefiero el primero.
fuente