Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Anonymous function and local variables

Say you have a button on your form. You attached an anonymous function to button's Click event:

void Test()
{
  int x = 10;
  btn.Click += (sender, e) => { MessageBox.Show(x.ToString()); };
}

This works as expected and displays 10; means it can access local variables. My question is how and why? How does an anonymous function get access to the local context?

The actual problem I'm dealing with is that I need to upgrade (so to speak) this anonymous function to a regular function (event handler). But doing that means I'll lose access to the variable x. I can't pass it in as a parameter too because then I'll not be able to attach it to Click event (signature mismatch). I can work around this by creating global variables and all that, but how do anonymous functions make it possible to access things that were outside their scope?

like image 741
dotNET Avatar asked Dec 30 '14 08:12

dotNET


1 Answers

Half of the point of anonymous functions are that they can capture the context in which they're specified. It's extremely convenient to be able to do so - that's the "why" part.

The way the compiler does this is to create a new class in cases where it needs to. So your code would be converted to something like:

void Test()
{
    TestHelper helper = new TestHelper();
    helper.x = 10;

    btn.Click += helper.Method;
}

private class TestHelper
{
    public int x = 10;

    public void Method(object sender, EventArgs e)
    {
        MessageBox.Show(x.ToString());
    }
}

Every use of x within Test is converted into a use of helper.x for the appropriate instance. This is how variables with different lifetimes is covered too. For example, suppose you had a loop like this:

for (int i = 0; i < 10; i++)
{
    int x = i;
    // Use with some anonymous function
}

then it would create a new instance of TestHelper for each iteration of the loop... whereas if x had been declared outside the loop, there'd just be a single instance that all the anonymous functions would effectively share.

When it's just this that's captured, the compiler creates an instance method within the existing class instead of creating a helper class. When there are different scopes with potentially multiple anonymous functions which capture a variety of variables, things can get a lot more complicated, with some helper classes having references to instances of other helper classes, etc.

like image 193
Jon Skeet Avatar answered Nov 15 '22 09:11

Jon Skeet