初始代码:
for(int i=0;i<sprite_火灾扑救二级场景类别UI.Length;i++)
{
if(sprite_火灾扑救二级场景类别UI[i].name.Contains(EventSystem.current.currentSelectedGameObject.name.Replace("Button_","")))
{
GameObject go = Instantiate(prefab_Button场景类别);
go.transform.SetParent(scrollView_二级场景类别.transform.GetChild(0).GetChild(0));
go.GetComponent<Image>().sprite = sprite_火灾扑救二级场景类别UI[i];
go.name = "Button_" + sprite_火灾扑救二级场景类别UI[i].name;
//go.GetComponent<Button>().onClick.AddListener(delegate { Button二级场景类别(sprite_火灾扑救二级场景类别UI[i].name); });
go.GetComponent<Button>().onClick.AddListener(()=> Button二级场景类别(sprite_火灾扑救二级场景类别UI[i].name));
}
}
报错:
问题分析:
当您使用lambda表达式()=> Button二级场景类别(i)
时,i
是被“捕获”为闭包中的变量。但是,由于lambda表达式是在for
循环中定义的,而for
循环会改变i
的值,因此所有通过lambda表达式添加的监听器实际上都会捕获到循环结束时的i
的最终值,而不是在添加监听器时的当前i
值。
为了解决这个问题,您需要在每次迭代中“固定”i
的值。这通常可以通过在循环内部创建一个新的局部变量来实现,该变量在每次迭代时都会被赋予i
的当前值。然后,您可以在lambda表达式中使用这个新的局部变量。但是,由于C#的闭包特性,直接这样做通常仍然会引用外部变量i
(除非您显式地创建一个新的作用域,如通过另一个方法调用或局部变量)。
然而,在Unity的上下文中,有一个更简单的方法可以使用:您可以利用Button
组件的name
或其他唯一属性来存储或识别需要传递给Button二级场景类别
方法的值,而不是直接传递i
。然后,在监听器内部,您可以根据按钮的这些信息来查找或计算出正确的值。
修改后:
for(int i=0;i<sprite_火灾扑救二级场景类别UI.Length;i++)
{
if(sprite_火灾扑救二级场景类别UI[i].name.Contains(EventSystem.current.currentSelectedGameObject.name.Replace("Button_","")))
{
GameObject go = Instantiate(prefab_Button场景类别);
go.transform.SetParent(scrollView_二级场景类别.transform.GetChild(0).GetChild(0));
go.GetComponent<Image>().sprite = sprite_火灾扑救二级场景类别UI[i];
go.name = "Button_" + sprite_火灾扑救二级场景类别UI[i].name;
string name = sprite_火灾扑救二级场景类别UI[i].name;
//go.GetComponent<Button>().onClick.AddListener(delegate { Button二级场景类别(sprite_火灾扑救二级场景类别UI[i].name); });
go.GetComponent<Button>().onClick.AddListener(()=> Button二级场景类别(name));
}
}