统一使用带有参数的脚本编程添加按钮

arm*_*ong 1 c# lambda unity-game-engine

我有一些按钮,每个按钮代表某个级别,并且想要以编程方式添加侦听器,但不太熟悉 C# 的 lambda 函数(也许是一些闭包的东西?),这就是我现在所做的:

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");
   });
}
Run Code Online (Sandbox Code Playgroud)

但是这条线:

ApplicationModel.currentLevel = levels[i];
Run Code Online (Sandbox Code Playgroud)

levels是一个List<Level>并且ApplicationModel是一个根据这篇文章保存信息的类 ,但它不断给出 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)
Run Code Online (Sandbox Code Playgroud)

Ous*_* D. 5

它不断给出 ArgumentOutOfRangeException:

您遇到的问题是,当i使用该变量时,for 循环已完成,并且 的i值为levels.Count

这称为捕获变量:

  • 变量的值是在使用它时而不是在捕获它时。
  • 捕获的变量的生命周期会延长,直到引用该变量的所有闭包都符合垃圾回收的条件。

相反,您可以做的是创建一个诱饵变量(让我们调用它)capturedIndex并让 lambda 表达式捕获capturedIndexfor 循环的索引器而不是索引器。

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");
    });
}
Run Code Online (Sandbox Code Playgroud)

进一步阅读: