2010-04-29 4 views
25

의 사소한 예에 "무한"는 IEnumerable은"무한"IEnumerable을 처리하는 방법은 무엇입니까?

foreach(int i in Numbers().Take(10)) { 
    Console.WriteLine(i); 
} 

var q = Numbers(); 
foreach(int i in q.Take(10)) { 
    Console.WriteLine(i); 
} 

모두 잘 작동 (그리고 수 0-에서 인쇄하는 것이 내가 아는

IEnumerable<int> Numbers() { 
    int i=0; 
    while(true) { 
    yield return unchecked(i++); 
    } 
} 

될 것 9).

q과 같은 표현을 복사하거나 처리 할 때 어떤 함정이 있습니까? 나는 항상 "게으른"평가를 받았다는 사실에 의지 할 수 있습니까? 무한 루프를 만들 위험이 있습니까?

+1

"Intin32.MaxValue = i32 + ++ 일 때"무한한 "예제가 예외를 throw하지 않을까요?또는 Int32.MinValue로 이동합니까? 흠 ..... –

+0

당신 말이 맞아요. 그것은 아마도 오버 플로우 예외를 던질 것입니다 ... 나는 그것을 편집 할 것입니다. – Danvil

+0

여기 까다 롭지 만, 당신의 요점은 여전히 ​​나타났습니다. :) 또한, 나는 그것을 시도하고 Int32.MinValue에 루프 않습니다. OverflowException이 없기 때문에 사실 무한 루프였습니다. –

답변

8

예, 위의 코드가 지연 실행됩니다. 당신이 영원히 코드 를 루프 거라고처럼 (코드에) 보이지만 실제로는 다음과 같이 생성합니다

IEnumerable<int> Numbers() 
{ 
    return new PrivateNumbersEnumerable(); 
} 

private class PrivateNumbersEnumerable : IEnumerable<int> 
{ 
    public IEnumerator<int> GetEnumerator() 
    { 
     return new PrivateNumbersEnumerator(); 
    } 
} 

private class PrivateNumbersEnumerator : IEnumerator<int> 
{ 
    private int i; 

    public bool MoveNext() { i++; return true; } 

    public int Current 
    { 
     get { return i; } 
    } 
} 

(이 분명하지를 이 꽤 있기 때문에, 생성됩니다 정확히 그럼에도 불구하고 이와 비슷하지만 느슨하게 평가 될 이유를 보여 주어야합니다.

18

게으른 버퍼없는 방법 만 호출하면 괜찮을 것입니다. 그래서 Skip, Take, Select 등 괜찮습니다. 그러나 Min, Count, OrderBy 등은 미쳐 갈 것입니다.

효과가 있지만 신중해야합니다. 또는 안전 조치 (또는 너무 많은 데이터 이후에 예외를 throw하는 다른 사용자 지정 확장 메서드)로 Take(somethingFinite)을 삽입하십시오. 예를 들어

:

public static IEnumerable<T> SanityCheck<T>(this IEnumerable<T> data, int max) { 
    int i = 0; 
    foreach(T item in data) { 
     if(++i >= max) throw new InvalidOperationException(); 
     yield return item; 
    } 
} 
+1

+1 경쟁 응답이 있지만 +1을 지정해야합니다. * SanityCheck *라고하는 IEnumerable의 확장 메소드에 대해. 최고의 함수 이름. 구현할 것입니다. ... –

+0

+1이 지적하고 있습니다 .OP가 실제로 foreach (int i in Numbers())를 호출하면 + '그것은 또한 문제를 일으킬 것입니다. – Felype

4

당신은 끝까지 읽으려고 어떤 욕심 기능을하지 않도록해야합니다. 이 같은 Enumerable 확장이 포함됩니다 : Count, ToArray/ToList을하고, Avg/Min/Max 집계 등

이 무한 게으른 목록 아무 문제가 없다, 그러나 당신이 그 (것)들을 처리하는 방법에 대한 의식을 결정해야합니다.

Take을 사용하면 모두 필요하지 않더라도 상한을 설정하여 무한 루프의 영향을 제한 할 수 있습니다.

2

예, 코드는 항상 무한 반복없이 작동합니다. 나중에 누군가가 와서 물건을 엉망으로 만들 수도 있습니다. 그들이하고 싶어한다고 가정 해 보자.

var q = Numbers().ToList(); 

그런 다음, 당신은 물에 젖었습니다! 많은 "집계"기능은 Max()처럼 당신을 죽일 것입니다.

0

게으른 평가가 아니라면 첫 번째 예가 첫 번째 예상대로 작동하지 않습니다.

관련 문제