Add listener to multiple buttons

I have a menuController that creates a matrix of buttons which represent the levels. When a certain button is clicked, that level should be loaded. However, it doesn’t matter which button I click, I always get level 25 returned… altough the highest possible level is only 20.
I think this has something to do with the lambda expression that is set to every button over and over but I don’t know how to fix this.

public class MenuController : MonoBehaviour {
    
        public GameObject btnLevelPrefab;
        public GameObject levelContainer;
        public GameObject communicationManager;
    
        private GameObject[,] btnLevels;
    
    	void Start () {
            btnLevels = new GameObject[4, 5];
    
    	    for(int i = 0; i < 5; i++)
            {
                for(int j = 0; j < 4; j++)
                {
                    btnLevels[j,i] = Instantiate(btnLevelPrefab, new Vector3(63 + j*90, 500 - i*90, 0), Quaternion.identity) as GameObject;
                    btnLevels[j,i].transform.SetParent(levelContainer.transform);
                    btnLevels[j,i].GetComponentInChildren<Text>().text = (j+1+i*4).ToString();
                    btnLevels[j,i].GetComponent<Button>().onClick.AddListener(() => { startLevel(j + 1 + i * 4); });
                }
            }
    	}
    	
    	private void startLevel(int level)
        {
            Debug.Log(level); // Returns 25 everytime???
            communicationManager.GetComponent<CommunicationManager>().setLevel(level);
            Application.LoadLevel(1);
        }
    }

SOLUTION!!

For some reason the AddListener can only be attached to every single button when I send the button as parameter instead of an integer that represents the level.

The new working code is now:

for(int i = 0; i < 5; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                btnLevels[j,i] = Instantiate(btnLevelPrefab, new Vector3(63 + j*90, 500 - i*90, 0), Quaternion.identity) as GameObject;
                btnLevels[j,i].transform.SetParent(levelContainer.transform);
                btnLevels[j,i].GetComponentInChildren<Text>().text = (j+1+i*4).ToString();
                Button btnTemp = btnLevels[j, i].GetComponent<Button>();
                btnLevels[j, i].GetComponent<Button>().onClick.AddListener(() => { startLevel(btnTemp); });

            }
        }
	}
	
	private void startLevel(Button btnLevel)
    {
        Debug.Log(btnLevel.GetComponentInChildren<Text>().text);
        communicationManager.GetComponent<CommunicationManager>().setLevel(int.Parse(btnLevel.GetComponentInChildren<Text>().text));
        Application.LoadLevel(1);
    }

The issue was that adding the functionality that way doesn’t preserve the state of the variables used inside it.

int i = 5;
AddListener(() => { function(i); });
i++;

This will call function(6) when clicked, because i later became 6. The fact that i was 5 when the listener was set up is irrelevant.

I’ve been burned by this before as well. I wish there was a way to say “The current value of” instead of “Whatever the value will be of” when doing that.

(j + 1 + i * 4)

may as well be

(4 + 1 + 5 * 4)

Which is 25.