Matt
Matt

Reputation: 1574

Event handler with lambda expression seems to have wrong parameter values

From this answer https://stackoverflow.com/a/6457528/299110

I'm using ctrl.PreRender += (sender, e) => ControlPreRender(ctrl, rule); to one or more controls within a foreach, with the values of ctrl and rule changing each time.

However when the ControlPreRender method is called, the rule parameter seems out of line with the sender the event handler was attached to.

I know I'm missing something here, not sure what though!

Update: Thanks for the answers, Eric Lippert's blogs really explained it. As suggested by the down-voter, I've put more of the code below, hopefully improving the question a bit:

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)
{
    // ...
}

Upvotes: 0

Views: 1012

Answers (2)

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174339

I think you want a temporary variable:

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

The reason is the following: Without that temporary variable, all your anonymous methods reference the same instance which changes as you loop through all your rules. This is called "access to modified closure". As erikkallen mentions, this has been fixed in C# 5.

You can easily check that yourself: Set a breakpoint in ControlPreRender and on the first breakpoint hit make an object ID for the rule parameter. You will see that at all the following hits of your breakpoint the rule parameter will have the same object ID which means it is the exact same instance.

Upvotes: 3

Olly
Olly

Reputation: 6026

Eric Lippert posted two excellent blog posts about this. You'll notice that they actually made a breaking change for .NET 4.5 to make the foreach loop behave as you might expect that it would. (Eric refers to C# 5, which confusingly is the compiler version used for .NET 4.5.) Eric says,

"This is the single most common incorrect bug report we get. That is, someone thinks they have found a bug in the compiler, but in fact the compiler is correct."

Note that @Daniel has already posted the correct code, as per Eric's post.

Upvotes: 1

Related Questions