Un ciclo foreach apparentemente crea un oggetto IEnumerator fuori dalla raccolta in cui lo si passa e quindi lo attraversa. Quindi un ciclo come questo:
foreach(var entry in collection)
{
entry.doThing();
}
si traduce in qualcosa di simile a questo:
(elimina un po 'di complessità riguardo al modo in cui l'enumeratore viene eliminato in seguito)
var enumerator = collection.GetEnumerator();
while(enumerator.MoveNext()) {
var entry = enumerator.Current;
entry.doThing();
}
Se questo viene compilato ingenuamente / direttamente, l'oggetto enumeratore viene allocato sull'heap (che richiede un po 'di tempo), anche se il suo tipo di base è una struttura - qualcosa chiamato boxe. Dopo che il ciclo è terminato, questa allocazione diventa spazzatura da ripulire in seguito e il gioco può balbettare per un momento se un sacco di spazzatura si accumula per consentire al raccoglitore di eseguire una scansione completa. Infine, il MoveNext
metodo e la Current
proprietà potrebbero comportare più passaggi di chiamata delle funzioni rispetto alla semplice acquisizione di un elemento direttamente collection[i]
, se il compilatore non incorpora tale azione.
I documenti Unity di Hellium sopra riportati indicano che questa forma ingenua è esattamente ciò che accade in Unity prima della versione 5.5 , se scorre su qualcosa di diverso da una matrice nativa.
Nella versione 5.6+ (comprese le versioni 2017), questa boxe non necessaria è sparita e non dovresti riscontrare allocazioni non necessarie se stai usando un tipo concreto (ad es. int[]
Oppure List<GameObject>
oppure Queue<T>
).
Otterrai comunque un'allocazione se il metodo in questione sa solo che sta funzionando con un qualche tipo di IList o altra interfaccia - in quei casi non sa con quale specifico enumeratore sta lavorando quindi deve prima inserirlo in un oggetto IEnumerator .
Quindi, c'è una buona possibilità che si tratti di vecchi consigli che non sono così importanti nello sviluppo moderno di Unity. Gli sviluppatori di unità come noi possono essere un po 'superstiziosi su cose che un tempo erano lente / pelose nelle vecchie versioni, quindi prendi qualsiasi consiglio di quella forma con un granello di sale. ;) Il motore si evolve più velocemente delle nostre convinzioni al riguardo.
In pratica, non ho mai avuto un gioco che mostrasse una notevole lentezza o singhiozzi di raccolta dei rifiuti dall'uso di cicli foreach, ma il tuo chilometraggio può variare. Crea il profilo del tuo gioco sull'hardware scelto per vedere se vale la pena preoccuparsi. Se è necessario, è piuttosto banale sostituire i loop foreach con espliciti per loop in seguito allo sviluppo, qualora si manifestasse un problema, quindi non sacrificherei la leggibilità e la facilità di codifica all'inizio dello sviluppo.