2012-07-04 1 views
11

Enumerable.RangeIDisposable을 구현하는지 궁금합니다.Enumerable.Range IDisposable을 구현하는 이유는 무엇입니까?

나는 IEnumerator<T>이 왜 그런지 이해하지만, IEnumerable<T>은 필요하지 않습니다.


는 (I, 나는 호기심 중에 중단 점을 배치했다 그것의 "소스 완료"방법

if (enumerable is IDisposable) 
    ((IDisposable)enumerable).Dispose(); 

같은 문이 내 .Memoise() 구현을 가지고 노는 동안이 발견 테스트에 의해 트리거되었습니다.)

+1

http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx –

답변

7

Enumerable.Range은 메서드 본문에 yield return을 사용합니다. yield return 문은 다음과 컴파일러의 마법에서, IDisposable를 구현하는 익명 형식을 생성합니다 그래서

[CompilerGenerated] 
private sealed class <GetNumbers>d__0 
    : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable 
{ 
    //the implementation 
    //note the interface is implemented explicitly 
    void IDisposable.Dispose() { } 
} 

: 컴파일 된 후

는이 같은 익명 중첩 클래스가
static IEnumerable<int> GetNumbers() 
{ 
    for (int i = 1; i < 10; i += 2) 
    { 
     yield return i; 
    } 
} 

결과 isIDisposable입니다. 이 예제에서는 Dispose 메서드가 비어 있습니다. 그 이유는 처형 될 필요가 없다는 것입니다. yield return 관리되지 않는 리소스가있는 형식 인 경우 다른 컴파일 결과가 나타날 수 있습니다. (확실하지 않음)

+0

컴파일러는 IEnumerable과 IEnumerator를 같은 클래스로 구현합니까? 흥미 롭 군. 나는 그 일에 대해 생각해야 할 것이다. – Fowl

+0

오, 이제 알겠습니다. 상태 머신을 사용하여 GetEnumerator가 여러 번 호출되었는지 여부를 감지하고 그렇지 않은 경우 자체를 반환합니다. – Fowl

+0

의미가 있습니다 만, 팩토리 메소드의 리턴 타입이 안티 패턴 인 것처럼 보이지 않는 경우, 팩토리 메소드는'IDisposable'을 구현하는 타입을 리턴합니다. 'yield return'을 통해 생성 된 컴파일러 생성 반복자는 'GetEnumerator()'가 호출 된 적이 없다면 처리하지 않고 포기하는 것이 실제로 무해한 유형으로 보일 수 있지만 일단 GetEnumerator()가 호출되면 일반적으로 처리가 필요합니다 . 덧붙여 말하면, GetEnumerable()이 적어도 한 번 호출 된 후에 반복자에 대해 Dispose를 호출하면 첫 번째 열거 자만이 무효화됩니다. – supercat