3

I have a situation where I have someFunction(int), and I need to generate programmatically n buttons that will call it. What this means is that I want to create buttons B1, B2, ... Bn that call someFunction(1), someFunction(2), ... someFunction(n) when clicked.

This is how I attempted to do this (semi-pseudocode):

for (int i = 1; i <= n; i++) {
  Button b = new Button();
  b.Caption = "Value " + n; // non-WPF: b.Text = "Value " + n;
  b.Click += (sender, event) => {
    someFunction(i);
  }
}

What bugs me about this is that when I click on the first button (B1), with a debugger over someFunction(i), it tells me that it's calling someFunction(n + 1).

I'm not sure why this is, or how to fix it. The work-around I use is to use, instead of someFunction(i), someFunction(int.Parse(i.ToString()) (to create a copy of i). But this seems shady to me, because integers should be value types.

2

2 Answers 2

2

I believe you understand WHY this happens. The problem is it captures the variable i itself, not its value. The workaround that seems better (without toString and int.parse) to me is to declare another local var that copies i

for (int i = 1; i <= n; i++) {
Button b = new Button();
  b.Caption = "Value " + n; // non-WPF: b.Text = "Value " + n;
  int locali = i;
  b.Click += (sender, event) => {
    someFunction(locali);
  }
}

This way the captured variable will be locali and it will remain the same across the loop.

Sign up to request clarification or add additional context in comments.

5 Comments

This is correct in spirit, but locali should be outside of the delegate, not inside.
@JSBangs why should it be declared outside? The scope is limited to the delegate call.
@JSBangs you are absolutely right. I guess I didn't pay much attention when I put it between the other code. @ashes999 It should be outside because if it's in the delegate the i will still get captured and ultimately the result will be the same.
As much as I like this solution, this seems like a hack/trick/work-around and not a proper solution. Is there a better way of doing this? (I'll accept this if it's the only answer and it works.)
You can read this. msdn.microsoft.com/en-us/library/bb763133.aspx It's for VB but the theory is the same, they work the same way. The local variable way is also the microsoft's solution of the problem (the unexpected behavour). EDIT: Another link: rongchaua.net/blog/…
1

Stormbreaker is correct, for more information see Eric Lippert's answer to this question

C# lambda, local variable value not taken when you think?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.