2010-12-20 2 views
0

대를 IEnumerable 일어나는가 나는이유는이 목록

public static void SomeMethod (List<SomeClass> group) 
{ 
    IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group 
              where gr.SomeProp== false 
              select gr); 
    foreach (SomeClass grFalse in groupWithFalse) 
    { 
     grFalse.Save(); 
    } 

    if (groupWithFalse.Any()) 
    { 
     // do some stuff 
    } 
} 

(는 단위 테스트의 많은에 사용 변경할 수 없습니다) DL 절약에 대한 모의 구현은 다음 BL 방법입니다있다 :

public void Save() 
{ 
    group.SomeProp = true; 
} 

만약 내가 단위 테스트를하려고하면 흐름의 마지막 문을 예를 들어 (groupWithFalse.Any()) 문이 실패로 분명히 그 속성이 false로 설정되어 더 이상 요소가 있습니다. I가 비즈니스 로직의 코드를 변경하는 경우 :

public static void SomeMethod (List<SomeClass> group) 
{ 
    List<SomeClass> groupWithFalse = new List<SomeClass>(); 
    foreach (var g in group) 
    { 
     if (g.SomeProp == false) 
      groupWithFalse.Add(g); 
    } 

    foreach (SomeClass grFalse in groupWithFalse) 
    { 
     grFalse.Save(); 
    } 

    if (groupWithFalse.Any()) 
    { 
     // do some stuff 
    } 
} 

조건문 if (groupWithFalse.Any()) 단위 테스트에 실패하지 않습니다. 왜 이런 일이 생길까요? 감사합니다.

+0

Google 'linq lazy evaluation' –

답변

3

LINQ 쿼리를 실행해도 결과가 저장되지 않습니다.
대신 열거 할 때마다 쿼리가 다시 실행됩니다.

Save()을 호출 한 후 항목이 where 절을 충족시키지 않아서 쿼리가 비어있게됩니다. List<T>에 결과를 저장합니다 ToList()를 호출

var unsaved = group.Where(g => !g.SomeProp).ToList(); 

변경을; 이렇게하면 쿼리를 다시 실행하지 않아도됩니다.

0

문제가 LINQ Lazy Evalution에 있습니다. 첫 번째 예에서 LINQ 쿼리는 실제로 두 번 실행됩니다. 첫 번째는 Save() 메서드를 호출하기위한 열거 형이고 두 번째는 Any()를 가져 오는 열거 형입니다.

일반적으로 LINQ로 작업하는 동안 각 쿼리마다 ToList()를 넣습니다.

2

deferred execution 때문에 문제가 발생했습니다. 첫 번째 예에서 groupWithFalseSomeProp이 거짓 인 개체 목록을 나타내지 않으며 해당 목록으로 평가할 수있는 쿼리를 나타냅니다.

당신이 당신의 목록이 전체 기능 동안 꼼짝 할 경우, 단순히 다음처럼 LINQ 쿼리의 끝에 .ToList()을 추가

IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group 
             where gr.SomeProp == false 
             select gr).ToList(); 
//            ^^^^^^^^^ 

이 쿼리 즉시을 을 실행하고 반환하게됩니다의 결과가 List<SomeClass>인데 그 내용이 이 아닌 경우이 변경됩니다.

0

좋아는 첫 번째 구현에 어떤 일이 일어나고하면 반복자 groupWithFalse을 정의하는 것입니다 그 false-SomeProp 세트가 group의 요소를 반복합니다. groupWithFalse을 반복했고 그 요소 모두에 대해 SomeProptrue으로 설정하고 다시 반복 할 때 (Any에 대한 호출이 두 번째 반복을 생성 함) 모든 요소는 SomeProptrue으로 설정합니다. 물론 Anyfalse을 반환합니다 (반복하면 빈 컬렉션이 생성됩니다).당신은 당신이 논리를 캡처 객체 (groupWithFalse)를 정의하는

IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group 
             where gr.SomeProp== false 
             select gr); 

을 말할 때

기본적으로, 조금 자세히 설명하기 위해 "나에게 false로 SomeProp 세트가 group의 요소의 순서를 제공합니다. " 명시 적으로이 객체는 실제로 SomeProp이 false로 설정된 요소의 컬렉션 또는 시퀀스가 ​​아닙니다. 처음으로이 객체 ( foreach)를 반복 할 때이 규칙은 SomePropfalse 인 요소를 생성합니다 ( group에있는 요소가있는 경우). 하지만 두 번째 반복 ( Any)하면이 규칙에서 요소를 가져 오는 컬렉션 group을 수정했기 때문에이 규칙은 요소를 생성하지 않습니다. List<SomeClass> 이름 groupWithFalse 당신이 바로 앞에있는 foreach 루프에에 요소를 추가했기 때문에 그렇지 않은 빈 콜렉션의 경우

는 두 번째 반복에서 당신은 확인된다. 여기

내가 코드를 작성합니다 방법은 다음과 같습니다

public static void SomeMethod (List<SomeClass> group) { 
    IEnumerable<SomeClass> groupWithFalse =(from SomeClass gr in group 
              where gr.SomeProp== false 
              select gr); 
    if(groupWithFalse.Any()) { 
     foreach (SomeClass grFalse in groupWithFalse) { 
      grFalse.Save(); 
     } 

     // do some stuff 
    } 
} 

이제 코드를 같이 읽고 "SomePropfalse되는 group의 요소를 가져옵니다 Any, Save이있는 경우이를 다음 몇 가지 물건을.."

0

첫 번째 예에서는 IEnumerable을 사용하고 있습니다. 객체의 목록이 아닌 쿼리와 같은 것으로 생각하십시오. 그래서 위의 "SomeProp이 false 인 요소 만 반복"이라는 쿼리를 사용하여 전체 그룹 "group"을 반복합니다.

그런 다음 foreach 문에서 "그룹"목록의 개체 상태를 수정합니다.

그런 다음 추가 쿼리 조건을 적용합니다. " 요소가"prop "가 false 인"group "목록에 있습니까? 그리고 당신은 분명히 "아무도 없다"라는 대답을 받는다.

두 번째 예제에서는 새로운 요소 컬렉션을 얻습니다. 쿼리가 아닙니다. 그럼 당신은 그것을 반복하고, 상태를 변경 한 다음 "어떤 요소입니까? 요소가 있습니까?"라고 묻습니다. 그리고 "예"라고 대답하십시오. 이전과 같은 요소가 있지만 SomeProp 속성 값이 변경되었습니다.