The issue here is that when you close over a variable what happens behind the scenes is that the compiler creates a new unnamed type, gives that type an instance field for every variable that is closed over in that block, gives it a method for every anonymous method in that code block and then passes a single instance of that object around.
This means that the lifetime of the first delegate is keeping that closure object alive, and it has a reference to the object b
, in addition to a
, internally, and vice versa.
Now in your case, it’s not an issue, as an Action
isn’t something that’s particularly memory intensive, so keeping it alive for a bit longer isn’t really a problem.
The C# team could, in theory, have ensured that in this particular case a new unnamed type could be created for each closure in the same block, but they chose not to as it makes the common case worse.