This is a common coding pitfall: you are using a loop increment in a callback function inside a loop construct. The callback function records the reference of the local variable i and reads it when it is called, but at this time i has already increased to the exit threshold.
Try this:
for (int i = 0; i < panel.buttonActions.Count; i++)
{
var temp = i;
...
button.onClick.AddListener(() => panel.buttonActions[temp]());
}
Deeper explanation:
When a local variable is referenced in the delegate, it becomes a captured variable. this is a good explanation.
The for loop is actually a syntactic sugar, the scope of i is outside the for structure:
for (int i = 0; i < 10; i++)
{
//your code
}
is actually equivalent to:
int i = 0;
for (;;)
{
if(i < 10) break;
//your code
i++;
}
that is to say, the i used in each round of the loop points to the same local variable. The captured variable is also the same one. If a new variable(copied of i) scoped to the loop structure is used in each round of the loop, then the captured variable is different.