var ints = new List< int >( new[ ] {
1,
2,
3,
4,
5
} );
var first = true;
foreach( var v in ints ) {
if ( first ) {
for ( long i = 0 ; i < int.MaxValue ; ++i ) { //<-- The thing I iterate
ints.Add( 1 );
ints.RemoveAt( ints.Count - 1 );
}
ints.Add( 6 );
ints.Add( 7 );
}
Console.WriteLine( v );
first = false;
}
Si vous commentez la for
boucle interne , cela lève, c'est évidemment parce que nous avons apporté des modifications à la collection.
Maintenant, si vous le décommentez, pourquoi cette boucle nous permet-elle d'ajouter ces deux éléments? Cela prend un certain temps pour l'exécuter comme une demi-minute (sur un processeur Pentium), mais cela ne lance pas, et le plus drôle est qu'il génère:
C'était un peu attendu, mais cela indique que nous pouvons changer et cela change réellement la collection. Des idées pourquoi ce comportement se produit?
c#
collections
LyingOnTheSky
la source
la source
int.MaxValue
itérations ...Réponses:
Le problème est que la manière de
List<T>
détecter les modifications consiste à conserver un champ de version, de typeint
, en l'incrémentant à chaque modification. Par conséquent, si vous avez fait exactement un multiple de 2 32 modifications à la liste entre les itérations, cela rendra ces modifications invisibles en ce qui concerne la détection. (Il débordera deint.MaxValue
versint.MinValue
et finira par revenir à sa valeur initiale.)Si vous modifiez à peu près n'importe quoi dans votre code - ajoutez 1 ou 3 valeurs au lieu de 2, ou réduisez le nombre d'itérations de votre boucle interne de 1, alors il lancera une exception comme prévu.
(Il s'agit d'un détail d'implémentation plutôt que d'un comportement spécifié - et c'est un détail d'implémentation qui peut être observé comme un bogue dans un cas très rare. Il serait cependant très inhabituel de le voir causer un problème dans un programme réel.)
la source
_version
champ est unint
.InvalidOperationException
, ce qui n'est en fait pas toujours vrai. Bien entendu, cela dépend de la définition du "détail de mise en œuvre".