2011-09-16 6 views
1

이 함수를 사용하여 람다 함수의 ienumarable을 만들었습니다.lenda 함수의 ienumerable 반전

 static IEnumerable<Func<int>> MakeEnumerator(int[] values) 
    { 
     for (int a = 0; a < values.Length; a++) 
     { 
      yield return() => Values[a]; 
     } 
    } 

그런 다음 LINQ를 사용하여이 작업을 되돌릴 수 없거나 모든 값이 마지막 함수가되지 않고 배열로 변환 할 수 없습니다. 예제 코드 (이 코드는 응용 프로그램의 코드가 아니라는 것을 보여줍니다).

  int[] start = {1,2,3}; 

     IEnumerable<Func<int>> end = MakeEnumerator(start).Reverse<Func<int>>(); 

     foreach (Func<int> i in end) 
     { 
      Console.WriteLine(i()); 
     } 

문제는 MakeEnumerator 함수에 있다고 생각합니다. 어떻게 작동하게 만들거나 작동하는 교체 역 기능을 작성하려면 어떻게 수정해야합니까?

+0

Resharper와 같은 코드 검사 도구는이 상황에서 경고 및 경우에 따라 제안 된 솔루션을 표시합니다. –

답변

5

문제는 루프 변수를 캡처한다는 것입니다. 모든 대리인이 동일한 변수를 캡처하므로 사용 사례에서 대표자를 실행할 때까지 항상 ... values.Length + 1의 최신 값을 볼 수 있습니다. 당신은 단순히 대신에 복사 할 수 있습니다 :

for (int a = 0; a < values.Length; a++) 
{ 
    int copy = a; 
    yield return() => Values[copy]; 
} 

또는 (그리고 양호하게는 IMO) 현재이 같은 문제를 해결해야합니다 foreach 루프, 사용 : 더 나은 아직

foreach (int value in values) 
{ 
    int copy = value; 
    yield return() => copy; 
} 

또는 :

return values.Select(x => (Func<int>)(() => x)); 

또는

Func<int, Func<int>> projection = x =>() => x; 
return values.Select(projection); 

자세한 내용은 Eric Lippert의 블로그 게시물 "Closing over the loop variable considered harmful"을 참조하십시오. foreach의 동작은 C# 4.5에서 변경 될 수 있습니다.

+0

'foreach'에 대한 계획된 변경 사항과 관련하여 아직 확실한 부분이 있습니까? – BrokenGlass

+0

@BrokenGlass : Eric Lippert는 스택 오버플로에 대한 의견에서 변경 될 것이라는 자신감을 예측했습니다. 나는 블로그 포스트에서 결정적인 것을 보지 못했다. –

+0

왜 단순히'yield return() => value; '라고 쓰지 않았습니까? – Nawaz

2

모든 람다 식은 sharing the same a variable입니다.
루프가 완료된 후에 만 ​​호출하므로 a은 항상 3입니다. (이 루프 내부의 범위 이후)이 코드에서

for (int dontUse = 0; dontUse < values.Length; dontUse++) 
{ 
    int a = dontUse; 
    yield return() => Values[a]; 
} 

각 람다 식 자체 a 변수를 가져오고 이러한 별도의 변수는 절대 변하지 않을 :

당신은 각각 자신의 변수를 제공해야합니다.