How to get a reliably ordered List of MonoBehaviours from the scene?

So basically I want to get MonoBehaviours in a list as I see them in the scene hierarchy view.

What should i do?

SceneManager.GetSceneAtScene.GetRootGameObjectsGameObject.GetComponentsInChildren should do it.

public static void GetAllMonoBehavioursInLoadedScenes(List<MonoBehaviour> addToList)
{
    for(int i = 0; i < SceneManager.sceneCount; i++)
    {
        foreach(var gameObject in SceneManager.GetSceneAt(i).GetRootGameObjects())
        {
            addToList.AddRange(gameObject.GetComponentsInChildren<MonoBehaviour>(true);
        }
    }
}
1 Like

@SisusCo
Quasi-related question: does implementation of foreach cache the collection reference? I’m always superstitious about it, which means I never actually managed to confirm this particular detail for myself, and maybe you have a definitive answer.

100% it does yes. Or perhaps, more accurately, it doesn’t need to.

foreach operates on IEnumerables. By writing:

foreach (var x in y) {

}

The compiler ultimately does something like this:

IEnumerator enumerator = y.GetEnumerator();
while (enumerator.MoveNext()) {
  var x = enumerator.Current;
 
  // your code inside the loop here
}

So really the reference to y is only used once, right at the beginning, to fetch an IEnumerator.

4 Likes

Exactly as @PraetorBlue said. The lowered code will be nearly identical regardless.

This:

foreach(int i in Enumerable.Range(0, 10))
{
    Debug.Log(i);
}

Gets lowered to this by the compiler:

IEnumerator<int> enumerator = Enumerable.Range(0, 10).GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        int current = enumerator.Current;
        Debug.Log(current);
    }
}
finally
{
    if (enumerator != null)
    {
        enumerator.Dispose();
    }
}

SharpLab is an awesome tool that can be used to verify this.