2011-08-20 7 views
5

이 코드를 고려하십시오.foreach와 list.ForEach() 사이의 클로저가 다른 점은 무엇입니까?

 var values = new List<int> {123, 432, 768}; 

     var funcs = new List<Func<int>>(); 

     values.ForEach(v=>funcs.Add(()=>v)); 

     funcs.ForEach(f=>Console.WriteLine(f()));//prints 123,432,768 

     funcs.Clear(); 

     foreach (var v1 in values) 
     { 
      funcs.Add(()=>v1); 
     } 

     foreach (var func in funcs) 
     { 
      Console.WriteLine(func()); //prints 768,768,768 
     } 

두 번째 foreach는 람다에 의해 캡처 된 종료 변수로 인해 768 번을 768 번 인쇄합니다. 첫 번째 경우에는 왜 발생하지 않습니까? foreach 키워드가 방법 Foreach과 다른 점은 무엇입니까? 단지 변수를 소개합니다 내가 values.ForEach

답변

9

foreach을 할 때 표현식이 평가 beacuse입니다. lambda 매개 변수 변수는 호출 될 때마다 "새로운"변수입니다.

입니다
foreach (var v1 in values) // v1 *same* variable each loop, value changed 
{ 
    var freshV1 = v1; // freshV1 is *new* variable each loop 
    funcs.Add(() => freshV1); 
} 

foreach (var func in funcs) 
{ 
    Console.WriteLine(func()); //prints 123,432,768 
} 

,

foreach (T v in ...) { } 

는 다음과 같이 생각할 수있다 :

T v; 
foreach(v in ...) {} 

해피 코딩

비교.

+1

감사합니다. 쓰기 위해 +1. –

6

의 차이는 foreach 루프에서, 당신은 캡처 된 단일 변수 v1을 가지고 있다는 것입니다. 이 변수는 values 내 각 값을 취합니다. 단 이면을 사용합니다 ... 이는 매번 최종 값만 볼 수 있음을 의미합니다.

버전에서 각 반복에는 새로운 변수 (f)가 도입되므로 각 람다 식은 값이 변하지 않는 별도의 변수를 캡처합니다.

Eric Lippert는 blogged about this입니다. 그러나이 동작은 일 수 있습니다. C#의 이후 버전에서는이 변경 될 수 있습니다.

+0

'foreach'의미를 이해합니다. 그러나'List .ForEach'에서 세 번째 줄에있는 변수'v'가 모든 반복에 대해 새로 생성된다는 것을 의미합니까? –

+0

@Ashley : 네, 람다 식의 매개 변수이기 때문에 가능합니다. 동일한 위임을 두 번 호출하고 람다 식 * 값을 수정 한 경우에도 캡쳐 된 변수가 아니라 대리자 매개 변수이므로 아무런 차이가 없습니다. –

+0

@ 존 (Jon), 회귀하지 않고 행동을 바꿀 수 있습니까? – FuleSnabel

관련 문제