2012-10-31 9 views
4

나는 Linq의 이상한 행동을 가로 질러 왔어 : 동일한 결과가 나는 것 같은 두 linq 표현과 함께! 한 번 루프하면 같은 결과를 얻지 만 위에는 아무것도 찾지 못합니다. 당신은 루프 변수를 통해 폐쇄하고 있다는Linq 이상한 행동 사전과

 Dictionary<String, String> mainDico = new Dictionary<String, String>(); 
     mainDico.Add("key1", "value1"); 
     mainDico.Add("key2", "value2"); 

     List<Dictionary<String, String>> ls = new List<Dictionary<String, String>>(); 

     Dictionary<String, String> fistDico = new Dictionary<String, String>(); 
     fistDico.Add("key1", "value1"); 
     fistDico.Add("key2", "value2"); 

     Dictionary<String, String> secondDico = new Dictionary<String, String>(); 
     secondDico.Add("key1", "other"); 
     secondDico.Add("key2", "other"); 

     ls.Add(fistDico); 
     ls.Add(secondDico); 


     IEnumerable<Dictionary<String, String>> failQuery = from p in ls 
                  select p; 

     IEnumerable<Dictionary<String, String>> successfulQuery = from p in ls 
                  select p; 

     String[] items = new String[] { "key1","key2" }; // with one element it works 

     foreach (var item in items) 
     { 
      String temp = mainDico[item]; 
      failQuery = failQuery.Where(p => p[item] == temp); 
      successfulQuery = successfulQuery.Where(p => p[item] == mainDico[item]); 
     } 

     Console.WriteLine(successfulQuery.SingleOrDefault() != null);//True 
     Console.WriteLine(failQuery.SingleOrDefault() != null);//False 
+0

코드를 복사/붙여 넣기 만하면 true, true가 출력됩니다. ..... –

+1

나는 3 대의 컴퓨터에 그것을 시도했다 : 진실한, 틀린 (DOT.NET 4.0) 그리고 당신의 코멘트 후에 다시 시도하십시오. – Akli

+4

L.B. 아마도 C# 5를 사용하고있을 것입니다. 그들은 클로저 처리 방법을 변경했습니다. http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx –

답변

5

문제는 다음과 같습니다

는 코드입니다. (당신은 정말 수정해야하며 첫 번째 경우), 그리고

foreach (var item in items) 
{ 
    String temp = mainDico[item]; 
    failQuery = failQuery.Where(p => p[item] == temp); 
    successfulQuery = successfulQuery.Where(p => p[item] == mainDico[item]); 
} 

당신은 두 번째 경우에 item 이상 닫 람다를 만드는 :

코드의 문제가있는 부분은 바로 여기 foreach 루프가 끝날 때까지 쿼리를 평가하지 않습니다. 즉, item은 foreach 루프의 마지막 항목이며 현재 항목이 아닙니다. 첫 번째 경우에서 수행하는 작업 인 새 로컬 변수를 생성하면 쉽게 해결할 수 있습니다. 이것이 그 이유입니다.

다음은이 문제를 더 자세히 논의하는 related link입니다. (당신은 "가까운 루프 변수를 통해"을 통해 검색하여 더 많이 찾을 수 있습니다.

는 혼란과 버그의 흔한 원인은 이후 this was changed in C# 5.0가. (이 특정 사람들이 문제를 재현 할 수없는 이유를 가능성이 있습니다.)

또한이 사전과 아무 상관이 있음을 주목할 필요가있다. 쿼리에서 item가 실패 이유입니다, 오히려 현재보다 항상 foreach의 마지막 항목 효과적이다. 의존 당신이 item했던 아무거나 현재 값이 원하는대로되지 않을 것입니다.

+0

신속하고 간결한 응답을 보내 주셔서 감사합니다! – Akli