The concept of closures related to lambda syntax in C # is a very big topic and too big for me to cover everything in this answer only, but at least try to answer a specific question. The actual answer is below, the rest between the background is necessary for understanding the answer.
What happens when the compiler tries to compile a method using anonymous methods is that it somehow rewrites the method.
Basically, a new class is created, and the anonymous method rises to this class. This gave a name, albeit an internal one, so for the compiler it is a kind of transition from an anonymous method to a named method. You, however, should not know or process this name.
Any variables that this method requires, variables that were declared in addition to the anonymous method, but in the same method that used / declared the anonymous method, will also be discarded, and then all changes to these variables will be overwritten.
There are several methods here, so it will be difficult for you to read the above text, so instead, give an example:
public Func<int, int> Test1() { int a = 42; return value => a + value; }
This method is rewritten something like this:
public Func<int, int> Test1() { var dummy = new <>c__DisplayClass1(); dummy.a = 42; return dummy.<Test1>b__0; } internal class <>c__DisplayClass1 { public int a; public int <Test1>b__0(int value) { return a + value; } }
The compiler can handle all these funky names (and yes, they are really named with all these brackets), because this applies to things with id identifiers and objects, the names are no longer a problem for the compiler. However, you can never declare a class or method with these names so that there is no risk that the compiler generates a class that just exists already exists.
Here is an LINQPad example that shows that the declared class, although with smaller brackets in its names, looks identical to the one generated by the compiler:
void Main() { var f1 = Test1(); f1(10).Dump(); f1.Dump(); var f2 = Test2(); f2(10).Dump(); f2.Dump(); } public Func<int, int> Test1() { int a = 42; return value => a + value; } public Func<int, int> Test2() { var dummy = new __c__DisplayClass1(); dummy.a = 42; return dummy._Test2_b__0; } public class __c__DisplayClass1 { public int a; public int _Test2_b__0(int value) { return a + value; } }
output:

If you look at the screenshot above, you will notice two things for each delegate variable, the Method property and the Target property.
When a method is called, it is called using the this link, which refers to the Target object. Thus, the delegate captures two things: which method to call and the object to which it can be called.
Basically, this object of this generated class is saved as part of the delegate because it is a method object.
With all of this in mind, let's look at your question:
Why does the lambda expression save the values of the variable scope after the method finishes?
A: If the lambda survives, all captured variables survive because they are no longer local variables of the method in which they were declared. Instead, they were raised to a new object, which also has a lambda method and thus “follows” the lambda wherever it goes.