2011-01-13 5 views
37

새 작업으로 게임을 처음 시도했지만 이해가되지 않는 일이 있습니다.foreach 루프에서 작업 시작 마지막 항목의 값

먼저 코드는 매우 간단합니다. 좀 이미지 파일 경로 목록을 전달하고, 그들 각각을 처리하는 작업을 추가하려고 : 내가 찾은

public Boolean AddPictures(IList<string> paths) 
{ 
    Boolean result = (paths.Count > 0); 
    List<Task> tasks = new List<Task>(paths.Count); 

    foreach (string path in paths) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       Boolean taskResult = ProcessPicture(path); 
       return taskResult; 
      }); 
     task.ContinueWith(t => result &= t.Result); 
     tasks.Add(task); 
    } 

    Task.WaitAll(tasks.ToArray()); 

    return result; 
} 

난 그냥 말,이 실행, 3의 목록을 해주면 것을 세 가지 작업 모두가 제공된 목록의 마지막 경로를 사용합니다. 단계별로 진행하면 (그리고 루프 처리 속도가 느려짐) 루프의 각 경로가 사용됩니다.

누군가가 무슨 일이 일어나고 있는지 설명해주십시오. 왜 그런가요? 가능한 해결 방법은 무엇입니까? 당신이 StartNew에 전달하는

+3

내가 ReSharper에서를 사용하는 것이 좋습니다 수 :(거의 모든 사람을 잡는다이 특정 오류 및 기타 잠재적 인 버그는 나무와 모두를위한 –

답변

73

루프 변수를 닫습니다. 그러지 마. 대신 사본을 가지고 :

foreach (string path in paths) 
{ 
    string pathCopy = path; 
    var task = Task.Factory.StartNew(() => 
     { 
      Boolean taskResult = ProcessPicture(pathCopy); 
      return taskResult; 
     }); 
    task.ContinueWith(t => result &= t.Result); 
    tasks.Add(task); 
} 

현재 코드는 path를 캡처 - 아니 당신이 작업을 만들 그것의 하지만 변수 자체를. 이 변수는 루프를 돌 때마다 값을 변경하므로 대리인이 호출 될 때 쉽게 변경할 수 있습니다. 변수의 복사본을 가지고 가서

, 당신이 루프를 통해 갈 때마다 새로운 변수를 도입하고 - 당신이 변수를 캡처 할 때, 그것은 루프의 다음 반복에서 변경되지 않습니다 .

에릭 리 퍼트 (Eric Lippert)는이 블로그에 더 많은 내용을 담은 블로그 게시물을 가지고 있습니다 : part 1; part 2.

가 기분 나빠하지 마십시오 -..이

+1

하지만 물론 숲에 대한 highlighten된다. :) –

+1

이 closure 문제와 Random()의 적절한 사용은 주파수가 상위 5 인 SO – BrokenGlass

+0

에 있어야합니다.이 "버그"(원래 * 의도적으로 * 였음)는 C# 5.0 –

12

람다는 각 반복에 변화 path 변수를 참조하는 (즉, 당신의 람다는 참조 path,보다는 그 값을 사용하고있다). 변경 될 버전을 가리 키지 않도록 로컬 사본을 생성 할 수 있습니다.

관련 문제