Reputation: 281
Say I have a C# method like this
public void MyMethod()
{
int i = 0;
var thread = new Thread(() =>
{
Thread.Sleep(100);
if (i == 0)
{
Console.WriteLine("Value not changed and is {0}", i);
}
else
{
Console.WriteLine(" Value changed to {0}.", i);
}
});
thread.Start();
i = 1;
}
Here method creates a thread which access the local variable created in method. By the time it access this variable the method has finished and thus a local variable i should not exist. But the code runs without any trouble. As per my understanding local variable do not exist after the method block finishes.I am not able to get this.
Upvotes: 10
Views: 1018
Reputation: 81179
A C# compiler typically converts C# code to an intermediate "language" called MSIL which, like C#, has local variables. Local variables in MSIL behave as you expect C# variables to behave: they cease to exist when the routine in which they are defined exits. Further, when C# code which uses local variables is translated into MSIL code which uses local variables, those C# variables behave like MSIL ones: they cease to exist when the defining function exits. Not all C# code which uses local variables, however, uses MSIL local variables to store them.
In various situations, the compiler will take code which is written to use local variables and, before translating it to MSIL, rewrite it so that it defines a new class object which contains fields for the variables in question, and then rewrite accesses to those variables so they instead access the new fields. If the "variables" are used by a delegate, the delegate will be given a reference to that new class object. Even if the function where the object was defined exits, the object itself will continue to exist as long as anything, including any copy of the delegate, holds a reference.
The rules that determine when a compiler uses MSIL local variables and when it rewrites things to use class fields can be tricky, and it's possible for small changes to part of a routine to change the semantics of other seemingly-unrelated parts.
Upvotes: 0
Reputation: 660148
As per my understanding local variables do not exist after the method block finishes.I am not able to get this.
Your understanding is simply wrong. The defining characteristic of a local variable is that its name is only in scope inside its declaring block. That's why it is called a "local" variable -- because its name is only visible locally.
You believe the falsehood that "local" means "short lived". That is incorrect; a local variable is short lived when it can be, but there are three situations in which it cannot be: when it is the closed-over outer variable of an anonymous function, when it is in an iterator block, or when it is in an async block.
Coincidentally your question was the subject of my blog last week; see it for more details:
Upvotes: 5
Reputation: 7365
The lambda expression that you have launched as a new thread creates a closure on i; since closures close on the variable and not the value, the thread references the same object as the outer scope and will be able to access its variables even after that outer scope has ended.
Upvotes: 0
Reputation: 564441
This works because the compiler rewrites your code to use a closure.
Since you use the variable within a lambda, the variable ends up getting changed to be a member of a class. The compiled code doesn't contain a local variable for i - even though you wrote it that way. Instead, it rewrites your code to use a compiler-generated class which contains an Int32 as a member variable, and the "local code" as well as the lambda refer to this class member instead.
For details, see this blog post on closures which gives you a rough sense of what the compiler does here.
Upvotes: 15