C# 具有lambda表达式的事件处理程序似乎具有错误的参数值

C# 具有lambda表达式的事件处理程序似乎具有错误的参数值,c#,events,event-handling,lambda,C#,Events,Event Handling,Lambda,从这个答案 我使用的是ctrl.PreRender+=(sender,e)=>ControlPreRender(ctrl,rule)到foreach中的一个或多个控件,ctrl和rule的值每次都会更改 但是,当调用ControlPreRender方法时,规则参数似乎与事件处理程序附加到的发送方不一致 我知道我错过了一些东西,但不知道是什么 更新: 谢谢你的回答,Eric Lippert的博客真的解释了这一点。正如落选者所建议的,我在下面添加了更多代码,希望能稍微改进一下这个问题: foreac

从这个答案

我使用的是
ctrl.PreRender+=(sender,e)=>ControlPreRender(ctrl,rule)
foreach
中的一个或多个控件,ctrl和rule的值每次都会更改

但是,当调用
ControlPreRender
方法时,
规则
参数似乎与事件处理程序附加到的发送方不一致

我知道我错过了一些东西,但不知道是什么

更新: 谢谢你的回答,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,这意味着它是完全相同的实例。

我想您需要一个临时变量:

foreach(var rule in rules)
{
    var tmpRule = rule;
    ctrl.PreRender += (sender, e) => ControlPreRender(sender as Control, tmpRule);
}
原因如下:如果没有这个临时变量,所有匿名方法都会引用同一个实例,当您循环遍历所有规则时,该实例会发生变化。这就是所谓的。正如erikkallen提到的,这在C#5中已经得到了修复

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

Eric Lippert对此发表了相关文章。您会注意到,他们实际上对.NET4.5做了一个突破性的更改,以使foreach循环的行为符合您的预期。(Eric指的是C#5,令人困惑的是C#5是用于.NET 4.5的编译器版本。)Eric说

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

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

Eric Lippert发布了关于此的信息。您会注意到,他们实际上对.NET4.5做了一个突破性的更改,以使foreach循环的行为符合您的预期。(Eric指的是C#5,令人困惑的是C#5是用于.NET 4.5的编译器版本。)Eric说

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


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

想法是。。。哪个?另外,您可以显示更多的代码吗?否则,我们无法判断您在匿名方法中使用的局部变量
ctrl
rule
会发生什么情况。这可能与此有关:
rule
的范围是什么?闻起来像是在修改一个封闭变量…这个想法是。。。哪个?另外,您可以显示更多的代码吗?否则,我们无法判断您在匿名方法中使用的局部变量
ctrl
rule
会发生什么情况。这可能与此有关:
rule
的范围是什么?对我来说,这闻起来像是在修改一个封闭变量……请注意:这在C#5中发生了更改:根据操作,即使ctrl在循环中也在更改……除了为ctrl引入另一个临时值之外,ControlPreRender(ctrl,tmpRule)也可以简单地更改为ControlPreRender(sender,tmpRule)作为记录:这在C#5中发生了变化:根据OP,甚至ctrl在循环中也发生了变化……除了为ctrl引入另一个临时值之外,ControlPreRender(ctrl,tmpRule)可以简单地更改为ControlPreRender(sender,tmpRule)。这确实是一个C#的东西,而不是.NET的东西。它是在C#5中修复的,而不是在.NET4.5中。因此,以.NET 4为目标的C#5仍然会修复这种行为,因为导致这种行为的是C#编译器,而不是.NET运行时。感谢您的澄清。这确实是C#的事情,而不是.NET的事情。它是在C#5中修复的,而不是在.NET4.5中。因此,以.NET 4为目标的C#5仍然会修复这种行为,因为导致这种行为的是C#编译器,而不是.NET运行时。感谢您的澄清。