다음 LINQ 문은 어떻게 작동합니까?


160

다음은 어떻게합니까 LINQ 문 작동합니까?

내 코드는 다음과 같습니다.

var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0);
list.Add(8);
foreach (var i in even)
{
    Console.WriteLine(i);
}

산출: 2, 4, 6, 8

왜 안돼 2, 4, 6?


102
쿼리 식의 결과는 쿼리 실행이 아니라 쿼리입니다.
Eric Lippert

6
정보가 적 으면 이 질문에 대한 대답을 참조하십시오 .
Daniel

9
분명히 질문을 실제로 요약 한 제목을 생각할 수 있습니다.
매트 볼

2
downvotes (내가 아니라 지금까지 6)에 대한 나의 추측은 그들이 질문 제목을 좋은 질문으로 너무 일반적이라고 생각한다는 것입니다. 그러나 뉴스 레터에서 투표 수를 확인하고 금주의 주요 질문이되는 것은 너무 걱정할 필요가 없다고 생각합니다.
Abel

답변:


235

결과는 실행 지연 으로 2,4,6,8인한 것입니다 .

쿼리 변수가 만들어 질 때가 아니라 쿼리 변수가 반복 될 때 쿼리가 실제로 실행됩니다. 이것을 지연된 실행이라고합니다.

-Suprotim Agarwal, "LINQ에서 지연된 쿼리와 즉각적인 쿼리 실행"

쿼리 결과를 캐싱하는 데 유용한 Immediate Query Execution 이라는 또 다른 실행이 있습니다 . Suprotim Agarwal에서 다시 :

단일 값을 생성하지 않는 쿼리를 즉시 실행하려면 쿼리 또는 쿼리 변수 에서 ToList(), ToDictionary(), ToArray(), Count(), Average()또는 Max()메서드를 호출하면 됩니다. 이를 변환 연산자라고하며 결과를 복사 / 스냅 샷 할 수 있으며 쿼리를 다시 실행할 필요없이 원하는만큼 액세스 할 수 있습니다.

출력을 원하면 다음을 2,4,6사용하십시오 .ToList().

var list = new List<int>{1,2,4,5,6};
var even = list.Where(m => m%2 == 0).ToList();
list.Add(8);
foreach (var i in even)
 {
    Console.WriteLine(i);
 }

8
Count (), Max (), Avg (), Sum () 및 전체 목록을 고려해야하는 다른 메소드도 쿼리 평가를 유발합니다.
Kenned

1
필자는 종종 'filterListList'를 메소드로 'filterList ()'대신 변수로 사용하는 것에 대해 생각했습니다. 아이디어는 메소드를 호출하는 대신 목록을 필터링 할 때마다 반복합니다. 특이하고 아마도 불완전한 성능 측면에서 일을하는 흥미로운 방법 일 수 있습니다.
Katana314

4
@Sebastian - 또한 Kenned의 코멘트 @에, .First(), .FirstOrDefault(), .Single().SingleOrDefault()또한 쿼리의 평가를 트리거합니다.
Scotty.NET

4
30 초 이내에 답변을 얻는 놀라운 방법 : D
MC

2
@MC 왜이 질문을했는지 모르겠습니다. 한 번에 전체 답변이 제공되지 않았습니다. 여러 번 편집되었습니다.
Atish Dipongkor-MVP

11

이는 지연된 실행으로 인해 발생했습니다. 즉, 표현식 계산은 어딘가에 필요할 때까지 실행되지 않습니다. 데이터가 너무 큰 경우 성능이 향상됩니다.


3
비싼 열거가 여러 번 실행되고 있음을 의미 할 수 있으므로 뉘앙스가있을 수 있습니다. 이러한 경우 성능이 저하 될 수 있습니다.
절망의 그리마

0

그 이유는 람다 식의 지연된 실행 때문입니다. foreach 루프에서 반복을 시작하면 쿼리가 실행됩니다.


11
기술적으로 람다가 아닌 반복자 의 지연된 실행입니다 .
D Stanley

0

LINQ에서 얻은 IEnumerable <>을 사용하면 열거 자 클래스 만 만들어지고 일부 워크 스테이션에서 사용하는 경우에만 반복이 시작됩니다.


-1

지연된 실행으로 인해이 결과를 얻습니다. 즉, 결과는 처음 액세스 할 때까지 실제로 평가되지 않습니다.

더 명확하게하기 위해 스 니펫 끝에 10을 목록에 추가하고 다시 인쇄하면 10을 출력하지 않습니다.

     var list = new List<int>{1,2,4,5,6};
    var even = list.Where(m => m%2 == 0).Tolist();
    list.Add(8);
    foreach (var i in even)
    {
        Console.WriteLine(i);
    }
//new*
    list.Add(10);
    foreach (var i in even)
    {
        Console.WriteLine(i);
    }

실제로 시도 했습니까? 나는 10출력을 얻는다 .
Mark Hurd

좋은 캐치 @MarkHurd yes는 .ToList ()를 추가하지 않았습니다. 게시물을 수정하여 예상 출력을 제공해야합니다. 내 기대는 표현이 처음으로 var를 사용할 때만 평가되었지만 매번 평가되는 것처럼 보입니다.
sandeep

이제 8두 출력에 포함되지 않습니다 .
Mark Hurd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.