Efectul secundar al implementării interne a listei

Efectul secundar al implementării interne a listei

Dacă faceți foreach pe unele List -u, atunci schimbarea foii iterate în interiorul bucla este foarte descurajată, deoarece aceasta este modalitatea corectă de a obține o InvalidOperationException. Și acum ghicitorul: ce credeți, ce se va întâmpla cu următorul cod:







Răspunsul corect este: acest cod va funcționa bine. Pe consolă veți vedea:

Soluția constă în implementarea internă a clasei List (vezi implementarea în MS.NET și Mono 3.10). Când iterăm, lista noastră ar trebui să monitorizeze cumva dacă o persoană a schimbat-o în următoarea iterație. Pentru aceasta, utilizați _versionul câmpului privat. Pentru orice operație, _versiunea este incrementată de 1. Când creați un Enumerator pentru o buclă, această valoare este reținută. și de fiecare dată când se numește MoveNext, verifică. că numărul versiunii nu sa schimbat. Dacă cineva a schimbat elementele colecției, atunci InvalidOperationException va fi aruncat.







Dar codul de mai sus funcționează bine fără excepții. De ce? Soluția este simplă: pentru stocarea _version, int este folosit. Și ce se va întâmpla dacă variabila int este mărită exact de 2 32 de ori? Se va reveni la valoarea inițială. În exemplu, bucla interioară (de la int.MinValue la int.MaxValue) modifică versiunea proastă exact de 2 32 -1 ori. Și linia list.Add (3) adaugă un element nou în foaie și face incrementarea finală a _version. care îl returnează la valoarea inițială. Ca urmare, data viitoare când este apelată MoveNext (), nimeni nu suspectează că am schimbat ceva. Crima perfectă.

Documentația ne spune. că ar trebui să fie aruncată o excepție dacă cineva a schimbat colecția. Deci, în mod oficial, acest exemplu ilustrează un bug mic. NET. Cu toate acestea, nu merită să ne îngrijorăm: probabilitatea de a se împiedica pe o problemă similară a vieții reale este destul de mică. Nu este necesar să țineți cont de un astfel de comportament și să îl luați în considerare cumva. ulterior se poate schimba (de exemplu, _versiunea va face 64 de biți).







Trimiteți-le prietenilor: