AddListener in foreach

Suddenly problem with lambda in foreach statement.

    Current.Nodes.ForEach( n => Debug.Log( n.name ) );// Outputs node0, node1
    foreach( Node node in Current.Nodes )
    {
        Node local_node = node;
        Button button = Instantiate( Resources.Load<Button>( "Prefabs/Button" ) );
        button.transform.SetParent( content );
        button.GetComponentInChildren<Text>().text = node.name;
        button.onClick.AddListener( () =>
        {
            Debug.Log( local_node.name );
        } );
    }

Clicking on buttons always prints node1

2 Answers

2

This is likely an issue with a closure around the local_node variable. Try copying the name of the node into a temporary local variable:

Current.Nodes.ForEach( n => Debug.Log( n.name ) );// Outputs node0, node1
     foreach( Node node in Current.Nodes )
     {
         string nodeName = node.name;
         Button button = Instantiate( Resources.Load<Button>( "Prefabs/Button" ) );
         button.transform.SetParent( content );
         button.GetComponentInChildren<Text>().text = nodeName ;
         button.onClick.AddListener( () =>
         {
             Debug.Log( nodeName  );
         } );
     }

Nope, same thing. By the way, local_node is temporary local variable too.

Yes, but I was thinking there may be an issue there related to capturing a reference type. But, I just tried something equivalent to your code and everything worked fine. Is there more to the code? Because right now it looks like all the buttons are being placed in the same location, which would mean only the top-most(last one) receives click events.

They are placed at ScrollView content with GridLayoutGroup.

[74067-nodes.png|74067]

Hmm I don't really see why this shouldn't be working. You could try converting the foreach to a for loop and accessing the Nodes by index in the lambda - note that you might have to copy the index into a local variable. I'd think these two would be equivalent, but maybe something strange is happening with the closure that I do not understand.

Everything because of this code is in couroutine. Here is the answer
http://answers.unity3d.com/answers/974195/view.html