foreach and transform.parent

Hi there,

I was trying to loop through all the children of a gameobject changing its parent (using c#). I was using the following code:

foreach (Transform tempTransform in transform){
		tempTransform.parent = null;
}

The code is pretty clean, but the problem is that it only changes some of the children (only the odd ones). I can do this in many other ways but this is by far the best. If I make any other action on it, for example rename them it works, the problem comes only when parenting

Any clues?

The child list is being updated when you re-parent inside that loop so the internal incrementation is skipping every 2nd one. Think of it as iterating over an array, but each time through the loop you change the size of the array you’re currently looping though - naturally things are going to go a bit wrong.

Building a copy of the list first should fix this problem.

Transform[] children = new Transform[](transform.childCount);
int i = 0;
foreach (Transform tempTransform in transform){
	children[i] = tempTransform;
	i++;
}
i = 0;
while(i < children.Length) {
	children[i].parent = null;
	i++
}

Caution ^^^ untested code.

Of course you can remove the first loop and replace it with

Transform[] children = GetComponentsInChildren<Transform>();

foreach (Transform tempTransform in children){
		tempTransform.parent = null;
}

The loop should be faster. GetComponentsInChildren is slow.

transform.DetachChildren();

Thank you all. Now I know why that happens. The “workaround” I was using was the one proposed by Cameron, but the other ones are also great for other situations.

Thanks all!

What happens is simple.

  1. Before you start the loop, your structure looks like this:

root
|-child1 ← This is the first element which gets called when you enter your loop
|-child2
|-child3
|-child4
|-child5
|-child6

So for each returns a reference to the first child, child1. When you do child1.parent = null; it will be removed from the structure.

root
|-child2 // You’re still in your FIRST iteration!!!
|-child3
|-child4
|-child5
|-child6

after that, the next element will be called, so the next iteration.

root
|-child2
|-child3 <— This is where your code points after the second iteration!
|-child4
|-child5
|-child6

What happend? Because you removed the first element, everything moved up. The child2 became 1st child, the child3 became 2nd child etc. On the next iteration it selected the next child, child3.

If transform changes while you’re inside the loop such effects can happen. With the examples from above, you first read all childs into a separate array, so no matter if “transform” changes, you already have all references to the childs you needed and this effects don’t happen

One of the way you could have done it with one for loop could have been:

for(int = transform.childCount; i > 0; i--) {
   transform[0].parent = null;
}

// or

while(transform.childCount > 0) {
    transform[0].parent = null;
}

This will always remove the top-most (aka first) transform, until “transform.childCount” is zero. However, this is not really recommended to do in general. It’s not very clean or readable. The code examples from above all make a better readable code. It’s just “for record”.

1 Like

Thanks for the explanation Tseng, it’s crystal clear now. :wink:

Sorry for responding to such an old thread but I stumbled upon this through google searches and figured others would to. I solved this by using a generic list . . .

//Dont forget to add:  using System.Collections.Generic; to the top of the script...

//create a new list
List<Transform> childrenList = new List<Transform>();

//add all children of the transform to the new list
foreach(Transform childTrans in transform)
  childTrans.Add(childTrans);

foreach(Transform childTrans in childrenList)
//do stuff
1 Like