闭包捕获问题(Closure Capture Issue)是编程中一个常见的陷阱,尤其在循环内创建委托(如Lambda表达式)时容易遇到。在C#中,闭包(Closure)会捕获变量本身,而不是变量的值,这可能导致循环中的多个委托共享同一个变量,最终得到意外的结果。
例子
for (int i = 0; i < 10; i++)
{
// 直接捕获循环变量i
btn[i].onClick.AddListener(() => AddDigit(i.ToString()));
}
这段代码有个问题,无论点击哪个按钮,最终传入 AddDigit 的值都会是 10(循环结束时 i 的值),而不是按钮对应的 0-9。
问题产生的原因
-
闭包捕获的是变量,不是值
- Lambda表达式
() => AddDigit(i.ToString())中的i是循环变量,而不是循环迭代时的值。 - 所有按钮的点击事件都会共享同一个变量
i。
- Lambda表达式
-
循环结束后变量
i的值是10- 当循环结束时,
i的值是10(因为循环条件是i < 10,最后一次循环后i++使其变成10)。 - 用户点击按钮时,事件触发的是当前
i的值,也就是10。
- 当循环结束时,
解决方法:
for (int i = 0; i < 10; i++)
{
int num = i; // 每次循环都创建一个新的num
btn[i].onClick.AddListener(() => AddDigit(num.ToString()));
}
其它闭包捕获问题的例子
for (int i = 0; i < 3; i++)
{
// 直接捕获i
Task.Run(() => Console.WriteLine(i));
}
输出结果可能是 3, 3, 3,而不是预期的 0, 1, 2。
2380

被折叠的 条评论
为什么被折叠?



