首页 > 解决方案 > 为什么这两个 c# 脚本给出不同的结果?

问题描述

我正在处理一个大的按钮列表,并尝试AddListener()使用快速的方式为该列表中的每个按钮

第一种方法是

btn[0] = CHbutt[0].GetComponent<Button>(); btn[0].onClick.AddListener(delegate { CH(0); });
btn[1] = CHbutt[1].GetComponent<Button>(); btn[1].onClick.AddListener(delegate { CH(1); });
btn[2] = CHbutt[2].GetComponent<Button>(); btn[2].onClick.AddListener(delegate { CH(2); });
btn[3] = CHbutt[3].GetComponent<Button>(); btn[3].onClick.AddListener(delegate { CH(3); });

它工作得很好,AddListener()对所有按钮都有效btn[];但是很多行...

第二种方式

for (int i = 0; i < CHmatt.Count; i++)
{
    btn[i] = CHbutt[i].GetComponent<Button>(); btn[i].onClick.AddListener(delegate { CH(i); });
}

但是这个不起作用,这个AddListener()只有最后一个按钮btn[0]

我很好奇这两个脚本之间的区别。

标签: c#unity3d

解决方案


这是一个捕获问题。更改代码如下,以避免捕获i

for (int i = 0; i < CHmatt.Count; i++)
{
    var ii = i;
    btn[i] = CHbutt[i].GetComponent<Button>(); 
    btn[i].onClick.AddListener(delegate { CH(ii); });
}

传递给AddListener函数的是一个delegate方法;但是,由于您传递的是循环迭代变量i,因此会捕获上下文i实际引用。随着循环的推进,所有捕获i的值都会发生变化,因此使这种方法“不起作用”。

通过引入一个本地副本i(这里名字不重要,我叫它ii),它在每次循环迭代时都超出范围,i避免了捕获,并将实际值ii传递给delegate方法(技术上,捕获,但它是每个循环迭代的副本i,因此不会随着更改而i更改。)


推荐阅读