You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor中for循环索引作为onclick参数失效,为何需重新赋值变量?

Blazor循环绑定事件的坑:为什么要重新赋值局部变量?

你遇到的这个问题和Blazor本身无关,本质是C#的循环变量作用域+闭包捕获机制搞的鬼,Blazor只是因为事件触发是延迟的,把这个问题放大了。

先掰明白循环变量的本质:

  • 你写的for循环里,row和col是在循环外面声明的,整个循环过程中用的是同一个变量实例——每次迭代只是更新它的数值,不是新建一个变量。
  • 当你给每个像素绑定@onclick="() => LogClickedPixel(row, col)"时,这个lambda表达式并没有直接把当时的row、col值存下来,而是捕获了这两个变量的引用。

问题就出在这:循环跑的速度比你点击像素快多了,等你点像素的时候,循环早跑完了,row和col已经变成了最后一次迭代的数值。这时候触发lambda,拿到的自然就是循环最后的那组值。

那为什么赋值给局部变量就好使?

  • 当你在循环内部写var currentRow = row; var currentCol = col;,这个currentRow和currentCol是每次迭代都会新建的独立变量,每个迭代的局部变量都有自己的作用域和数值。
  • lambda捕获的是当前迭代的局部变量引用,后续迭代不会修改它的值,所以点击对应像素时,就能拿到正确的row和col了。

举个代码对比更清楚:

错误写法(点击全传最后一组值)

@for (int row = 0; row < GridHeight; row++)
{
    @for (int col = 0; col < GridWidth; col++)
    {
        <div @onclick="() => LogClickedPixel(row, col)" class="pixel"></div>
    }
}

正确写法(点击传对应位置值)

@for (int row = 0; row < GridHeight; row++)
{
    @for (int col = 0; col < GridWidth; col++)
    {
        var currentRow = row;
        var currentCol = col;
        <div @onclick="() => LogClickedPixel(currentRow, currentCol)" class="pixel"></div>
    }
}

补充一句:这个坑不是Blazor独有的,C#里只要用闭包捕获for循环变量的场景都会踩——比如异步任务、定时器回调。另外,C# 5.0之后foreach循环的变量改成了每次迭代新建实例,但for循环至今还是老逻辑,所以得自己手动搞局部变量。

内容的提问来源于stack exchange,提问作者Ondrej Sevcak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 03:25:05