[Bug?] int parameter on dynamically added onClick-Event is wrong

Hey all,

I am making a shop where one can buy weapons. The UI-Buttons to buy the weapons are created dynamically.

If pressed, the button should call the function “BuyWeapon(i)” that gives the player the right weapon from a list, based on the parameter ‘i’ of the for-loop.

void Start(){
    for(int i = 0; i < weapons.Count; i++){
        Debug.Log(i);//returns i
        //Instantiate button-prefab
	    GameObject go = Instantiate(Resources.Load("Button"),Vector3.zero,container.rotation) as GameObject;

	    //Add function BuyWeapon() to onClick of current button
	    UnityEngine.Events.UnityAction buy = () => { this.BuyWeapon(i); };//passes i as parameter
	    go.GetComponent<Button>().onClick.AddListener(buy);
    }
}

public void BuyWeapon(int i){
    Debug.Log(i);//returns always weapons.Count, not buttons' index-parameter
    player.itemsList.Add(weapons*);*

}
However, if I click any button, I will get an OutOfRange-Error on the function BuyWeapon() because the parameter ‘i’ on each onClick-event is equals “weapons.Count”.
But on Start() ‘i’ will return its value and so it should pass it to the AddFunction-Part.
This is paradox.
Thanks in advance.

Yes, it’s a bug in your code. Your anonymous function is capturing the variable i, not the value of i. You must make a local copy of the variable i inside of the anonymous function. Otherwise you’re just getting whatever the last value of i is.

e.g…

int localIndex = i; 
buy = () => { this.BuyWeapon(localIndex); };

You can refer to this Stack Overflow question for more information.

And this 2 part article by Erik Lippert.