0

从这个答案https://stackoverflow.com/a/6457528/299110

我正在使用ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule);a 中的一个或多个控件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)
{
    // ...
}
4

2 回答 2

3

我想你想要一个临时变量:

foreach(var rule in rules)
{
    var tmpRule = rule;
    ctrl.PreRender += (sender, e) => ControlPreRender(sender as Control, tmpRule);
}

原因如下:如果没有该临时变量,所有匿名方法都会引用同一个实例,该实例会随着您遍历所有规则而发生变化。这称为“访问修改后的闭包”。正如 erikkallen 所提到的,这已在 C# 5 中得到修复。

您可以自己轻松地检查:ControlPreRender在第一个断点命中设置断点,为规则参数创建一个对象 ID。您将看到,在您的断点的所有以下命中,规则参数将具有相同的对象 ID,这意味着它是完全相同的实例。

于 2012-09-13T12:02:36.080 回答
1

Eric Lippert 发表了两篇关于此的优秀博客文章。您会注意到他们实际上对 .NET 4.5 进行了重大更改,以使 foreach 循环的行为符合您的预期。(Eric 指的是 C# 5,令人困惑的是,它是用于 .NET 4.5 的编译器版本。)Eric 说,

“这是我们得到的最常见的错误错误报告。也就是说,有人认为他们在编译器中发现了错误,但实际上编译器是正确的。”

请注意,@Daniel 已经按照 Eric 的帖子发布了正确的代码。

于 2012-09-13T12:08:59.430 回答