C#

[C#][Unity3D] List<T> Remove 사용 주의사항

Binceline 2013. 3. 7. 13:49

출처 : Unity3D.com



- Question

InvalidOperationException: The list was modified.

InvalidOperationException: The list was modified. Boo.Lang.List`1+c__Iterator6[UnityEngine.GameObject].MoveNext () Item.OnCollisionExit (UnityEngine.Collision collision) (at Assets/Item.js:73)

I simply want a list with item I currently collide with, so when I stop colliding they must be removed from the list:

EDIT: I changed my code but now it gives an index out of range exception

  1. function OnCollisionExit(collision : Collision) {
  2. for(var i = tegenstanders.Count; i> 0; i--)
  3. {
  4. item = tegenstanders[i];
  5. if(item.name == collision.gameObject.name)
  6. {
  7. tegenstanders.Remove(tegenstanders[i]);
  8. }
  9. }
  10. }

- Answer

This happens because you're removing items from the list at the same time as you are iterating through it. It's easier to explain if you convert the list to a non-enumerated for-loop instead:

  1. List<int> example = new List<int>();
  2. for (int i = 0; i < example.Count; i++)
  3. {
  4. if (something)
  5. example.Remove(example[i]); // Not safe to do
  6.  
  7. }

If you remove an item from the list while you're going through it, the for-loop's impression of the list's Count-property is no longer reliable, since the amount of elements in the list changed during execution of the loop. In addition, the enumeration is now messed up; example[i] now points to another item in the list, because the Remove-command has shifted all of the elements with a higher index down to keep them sequential in memory, so you would effectively skip an item if you kept iterating with it. That's why the enumerated version of the loop doesn't enjoy it very much when you modify the List in it.

To get around this issue, use a standard for-loop and iterate through the list backwards instead:

  1. List<int> example = new List<int>();
  2. for (int i = example.Count-1; i >= 0; i--)
  3. {
  4. if (something)
  5. example.Remove(example[i]); // Safe to do
  6. }

This is not a problem, because you're stopping iteration at 0, not at List.Count, and all of your indexes still point to the right elements just fine, because the elements get shifted down on Remove, and you've already iterated through those.


반응형