Un bucle foreach aparentemente crea un objeto IEnumerator de la colección que lo pasa y luego lo recorre. Entonces un bucle como este:
foreach(var entry in collection)
{
entry.doThing();
}
se traduce en algo parecido a esto:
(evitando cierta complejidad en torno a cómo se eliminará el enumerador más adelante)
var enumerator = collection.GetEnumerator();
while(enumerator.MoveNext()) {
var entry = enumerator.Current;
entry.doThing();
}
Si esto se compila ingenua / directamente, entonces ese objeto enumerador se asigna en el montón (lo que lleva un poco de tiempo), incluso si su tipo subyacente es una estructura, algo llamado boxeo. Después de completar el ciclo, esta asignación se convierte en basura para limpiar más tarde, y su juego puede tartamudear por un momento si se acumula suficiente basura para que el recolector ejecute un barrido completo. Por último, el MoveNext
método y la Current
propiedad podrían involucrar más pasos de llamada a funciones que simplemente tomar un elemento directamente collection[i]
, si el compilador no integra esa acción.
Los enlaces de Unity docs Hellium anteriores indican que esta forma ingenua es exactamente lo que sucede en Unity antes de la versión 5.5 , si se itera sobre otra cosa que no sea una matriz nativa.
En la versión 5.6+ (incluidas las versiones de 2017), este boxeo innecesario desapareció , y no debería experimentar una asignación innecesaria si está utilizando algún tipo concreto (por ejemplo, int[]
or List<GameObject>
o Queue<T>
).
Todavía obtendrá una asignación si el método en cuestión solo sabe que está funcionando con algún tipo de IList u otra interfaz ; en esos casos, no sabe con qué enumerador específico está trabajando, por lo que primero debe encajonarlo en un objeto IEnumerator .
Entonces, hay una buena posibilidad de que este sea un viejo consejo que no es tan importante en el desarrollo moderno de Unity. Los desarrolladores de Unity como nosotros pueden ser un poco supersticiosos acerca de las cosas que solían ser lentas / peludas en las versiones antiguas, así que toma cualquier consejo de esa forma con un grano de sal. ;) El motor evoluciona más rápido que nuestras creencias al respecto.
En la práctica, nunca he tenido un juego que muestre una notable lentitud o problemas de recolección de basura al usar bucles foreach, pero su millaje puede variar. Perfile su juego en su hardware elegido para ver si vale la pena preocuparse. Si es necesario, es bastante trivial reemplazar los bucles foreach con bucles explícitos para más adelante en el desarrollo en caso de que se manifieste un problema, por lo que no sacrificaría la legibilidad y la facilidad de codificación al principio del desarrollo.