Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
315 views
in Technique[技术] by (71.8m points)

C# lambda, local variable value not taken when you think?

Suppose we have the following code:

void AFunction()
{

   foreach(AClass i in AClassCollection)
   {
      listOfLambdaFunctions.AddLast(  () =>  {  PrintLine(i.name); }  );
   }
}

void Main()
{
    AFunction();
    foreach( var i in listOfLambdaFunctions)
       i();
}

One might think that the above code would out the same as the following:

void Main()
{

    foreach(AClass i in AClassCollection)
       PrintLine(i.name);
}

However, it doesn't. Instead, it prints the name of the last item in AClassCollection every time.

It appears as if the same item was being used in each lambda function. I suspect there might be some delay from when the lambda was created to when the lambda took a snapshot of the external variables used in it. Essentially, the lambda is holding a reference to the local variable i, instead of taking a "snapshot" of i's value when the lambda was created.

To test this theory, I tried this code:

string astr = "a string";
AFunc fnc = () => { System.Diagnostics.Debug.WriteLine(astr); };
astr = "changed";
fnc();

and, surprise, it outputs changed!

I am using XNA 3.1, and whichever version of C# that comes with it.


My questions are:

  1. What is going on?
  2. Does the lambda function somehow store a 'reference' to the variable or something?
  3. Is there any way around this problem?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is a modified closure

See: similar questions like Access to Modified Closure

To work around the issue you have to store a copy of the variable inside the scope of the for loop:

   foreach(AClass i in AClassCollection) 
   { 
      AClass anotherI= i;
      listOfLambdaFunctions.AddLast(  () =>  {  PrintLine(anotherI.name); }  ); 
   } 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...