I have some buttons each represents some level and want to add the listener programmatically, but not quite familiar with the lambda function of C#(maybe some closure thing?), It's what I do now:
for(int i=0; i<levels.Count; i++){
//omit the making a button snippet
button.GetComponent<Button>().onClick.AddListener(() =>
{
Debug.Log("load Scene");
ApplicationModel.currentLevel = levels[i];
SceneManager.LoadScene("Game");
//Application.LoadLevel("Game");
});
}
But the line:
ApplicationModel.currentLevel = levels[i];
levels
is a List<Level>
and ApplicationModel
is a class holding the info according to this post
but it keeps give a ArgumentOutOfRangeException:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
System.Collections.Generic.List`1[Level].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633)
GameLevelManger+<initScrollPanel>c__AnonStorey0.<>m__0 () (at Assets/GameLevelManger.cs:72)
答案 0 :(得分:2)
it keeps give a ArgumentOutOfRangeException:
the issue you're having is that by the time the variable i
is used the for loop has completed and the value of i
is levels.Count
.
this is referred to as captured variables:
Rather what you can do is kind of create a decoy variable let's call it capturedIndex
and let the lambda expression to capture the capturedIndex
rather than the indexer of the for loop.
for(int i=0; i<levels.Count; i++){
//omit the making a button snippet
int capturedIndex = i; // <-- let the lambda capture this rather than the indexer.
button.GetComponent<Button>().onClick.AddListener(() =>
{
Debug.Log("load Scene");
ApplicationModel.currentLevel = levels[capturedIndex];
SceneManager.LoadScene("Game");
//Application.LoadLevel("Game");
});
}
further reading: