根据这个答案https://stackoverflow.com/a/6457528/299110
我将ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);
用于foreach
中的一个或多个控件,每次ctrl和rule的值都会更改。
然而,当调用ControlPreRender
方法时,rule
参数似乎与事件处理程序所连接的发送方不一致
我知道我在这里错过了什么,但不确定是什么!
更新:感谢你的回答,Eric Lippert的博客真的解释了这一点。正如落选者所建议的,我在下面放了更多的代码,希望能稍微改进一下这个问题:
foreach (var ctrl in controls)
{
// ...
foreach (var rule in rules)
{
// ...
ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);
}
}
public static void ControlPreRender(Control ctrl, ControlRule rule)
{
// ...
}
我想你想要一个临时变量:
foreach(var rule in rules)
{
var tmpRule = rule;
ctrl.PreRender += (sender, e) => ControlPreRender(sender as Control, tmpRule);
}
原因如下:如果没有这个临时变量,所有匿名方法都会引用同一个实例,当您循环所有规则时,该实例会发生变化。这被称为"修改闭包的访问"。正如erikkallen提到的,这已经在C#5中得到了修复。
您可以很容易地自己检查:在ControlPreRender
中设置一个断点,并在第一个断点命中时为规则参数创建一个对象ID。您将看到,在断点的以下所有命中处,规则参数都将具有相同的对象ID,这意味着它是完全相同的实例。
Eric Lippert为此发布了两篇出色的博客文章。您会注意到,他们实际上对.NET4.5进行了突破性的更改,使foreach循环的行为与您预期的一样。(Eric指的是C#5,令人困惑的是,它是用于.NET 4.5的编译器版本。)Eric说,
"这是我们收到的最常见的错误错误错误报告。也就是说,有人认为他们在编译器中发现了错误,但事实上编译器是正确的。"
请注意,@Daniel已经根据Eric的帖子发布了正确的代码。