Prafulla
Prafulla

Reputation: 281

How thread can access local variable even after the method has finished?

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

Answers (5)

supercat
supercat

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

Eric Lippert
Eric Lippert

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:

http://blogs.msdn.com/b/ericlippert/archive/2012/01/16/what-is-the-defining-characteristic-of-a-local-variable.aspx

Upvotes: 5

Tetsujin no Oni
Tetsujin no Oni

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

Reed Copsey
Reed Copsey

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

SLaks
SLaks

Reputation: 887469

That's called a closure.
It extends local variables beyond the lifetime of the method.

Upvotes: 4

Related Questions