1

Similar to: How do closures work behind the scenes? (C#)

Assume we have code:

static void Main(string[] args)
{
  int i = 100;
  Action d = () => { i++; };
  d();

  Console.WriteLine(i.ToString());  
}

We will see the result "101".

I know that if anonymous function captures the local variable it creates a new class with field for local variable and method related to anonymous function.

So this class will look like(pseudocode):

 private class DisplayClass1
 {
     public int i;            
     public void Main(){ i++; }
 }

With ILDasm.exe we see generated class:

enter image description here

Then Main method of Program will look like(pseudocode):

static void Main(string[] args)
{
  int i = 100;

  //create helper class
  DisplayClass1 class1 = new DisplayClass1();
  //initialize fields
  class1.i = i;

  //crete instance of delegate
  Action d = new Action(class1.Main);

  d.Invoke();

  Console.WriteLine(i.ToString());
}

It is clear how it changes instance of the reference type. But how it works with struct?

I guess it adds one more row after d.Invoke(); like i = class1.i;(any problems with multithreading?) or do some special operations in DisplayClass1.Main to access the same variable from stack. Here is IL code of this method:

.method public hidebysig instance void  '<Main>b__0'() cil managed
{
  // Code size       16 (0x10)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  dup
  IL_0003:  ldfld      int32 ConsoleApplication3.Program/'<>c__DisplayClass1'::i
  IL_0008:  ldc.i4.1
  IL_0009:  add
  IL_000a:  stfld      int32 ConsoleApplication3.Program/'<>c__DisplayClass1'::i
  IL_000f:  ret
} // end of method '<>c__DisplayClass1'::'<Main>b__0'

I'm not specialist in MSIL. Any idea?

Community
  • 1
  • 1
  • What do you mean by "changes instance of the reference type"? – Jon Skeet Jan 20 '15 at 19:45
  • Agree. Its not right to say it. I mean we change object by reference. But if we assign other reference to `i` in `DisplayClass1` it will not work right.(here my mistake, isn't it?) As i see from Servy answer for both reference type and value type compiler generates the same code. – Yevgeniy Pokotylo Jan 20 '15 at 20:11

1 Answers1

1

Your pseudocode isn't quite right. It actually replaces all use of the local with the closure class's field:

static void Main(string[] args)
{
  //create helper class
  DisplayClass1 class1 = new DisplayClass1();
  //initialize fields
  class1.i = 100;

  //crete instance of delegate
  Action d = new Action(class1.Main);

  d.Invoke();

  Console.WriteLine(class1.i.ToString());
}
Servy
  • 202,030
  • 26
  • 332
  • 449
  • Thank! But how it deals if anonimous function captures not local variable but method argument? – Yevgeniy Pokotylo Jan 20 '15 at 19:52
  • @EugenePokotilo It'll copy the values from the arguments to the field of the close class when initializing the closure class, and then all uses of the parameter in the original code becomes uses of the closure class' corresponding field. – Servy Jan 20 '15 at 19:56
  • 1
    And now you know why you can't close over `ref` parameters. – Servy Jan 20 '15 at 20:00