2009-07-06 5 views
22

IEnumerable과 IEnumerator를 통과했지만 분명히 한 점을 얻을 수 없었습니다. foreach가 있으면이 두 인터페이스가 필요한 이유는 무엇입니까? 인터페이스를 사용해야하는 시나리오가 있습니까? 그렇다면 예를 들어 설명 할 수 있습니다. 제안 및 의견을 환영합니다. 감사합니다. .IEnumerable, IEnumerator 대 foreach, 사용시기

답변

46

foreach은 대부분 인터페이스가입니다. 시퀀스로 구현하고 foreach 시퀀스를 사용하려면 인터페이스가 필요합니다. (반복자 블록은 대개이 구현 작업을 매우 단순하게 만듭니다.)

그러나 가끔 반복기를 직접 사용하는 것이 유용 할 수 있습니다. 좋은 예가 두 개의 다른 시퀀스를 "쌍으로"만들려고 할 때입니다. 예를 들어 이름과 나이 중 하나와 둘을 함께 인쇄하려는 두 시퀀스를 수신했다고 가정합니다. 당신은 작성할 수 있습니다 : 당신이 경우 지금

public T Max<T>(IEnumerable<T> items) 
{ 
    Comparer<T> comparer = Comparer<T>.Default; 

    using (IEnumerator<T> iterator = items.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      throw new InvalidOperationException("No elements"); 
     } 
     T currentMax = iterator.Current; 

     // Now we've got an initial value, loop over the rest 
     while (iterator.MoveNext()) 
     { 
      T candidate = iterator.Current; 
      if (comparer.Compare(candidate, currentMax) > 0) 
      { 
       currentMax = candidate; 
      } 
     } 
     return currentMax; 
    } 
} 

:

static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages) 
{ 
    using (IEnumerator<int> ageIterator = ages.GetEnumerator()) 
    { 
     foreach (string name in names) 
     { 
      if (!ageIterator.MoveNext()) 
      { 
       throw new ArgumentException("Not enough ages"); 
      } 
      Console.WriteLine("{0} is {1} years old", name, ageIterator.Current); 
     } 
     if (ageIterator.MoveNext()) 
     { 
      throw new ArgumentException("Not enough names"); 
     } 

    } 
} 

는 마찬가지로 당신이 (말)을 치료하려는 경우 나머지 다른 첫 번째 항목을 반복자를 사용하는 것이 유용 할 수 있습니다 IEnumerator<T>IEnumerable<T>의 차이에 관심이 있으시면 데이터베이스 용어로 생각하면됩니다 : IEnumerable<T>을 테이블로 생각하고 IEnumerator<T>을 커서로 생각하십시오. 표를 요청하여 새 커서를 제공 할 수 있으며 같은 표에 여러 개의 커서를 동시에 가질 수 있습니다.

이 차이를 실제로 깨는 데는 시간이 걸릴 수 있지만 목록 (또는 배열 등)에 "목록에있는 위치"라는 개념이 없지만 목록의 반복자/배열/뭐든간에 않습니다 해당 비트가 도움이됩니다.

+0

모든 도움을 준 Jon에게 감사드립니다. 지금 받았고 더 명확하게 이해할 것입니다. 또한 다음 링크는 매우 유용합니다. http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

+0

이것은 IEnumerator를 사용하여 막힌 위치의 예입니다 효율적인 유지. http://stackoverflow.com/questions/1018407/what-is-the-most-elegant-way-to-get-a-set-of-items-by-index-from-a-collection/1025137#1025137 –

+0

@ 존 스키트 나는 당신이 코딩 한 방식을 정말 좋아했다. 방법. 나는 하나의 질문을했습니다. 당신은 IEnumberator와 함께 construct를 사용했다. 나는 그것을 사용하는 것이 그 안에 들어오는 것을 처분한다는 것을 안다. IEnumberator에서 왜 사용 했습니까? –

8

존이 말한 내용.

  • IEnumerable 또는 IEnumerable<T>은 : 객체가 당신에게 당신이 순서/수집을 통해 통과하는 데 사용할 수있는 반복자를 줄 수 있다고이를 구현하여/
  • IEnumerator 또는 IEnumerator<T>을 설정 : 사용자가 정의한 GetEnumerator 메서드를 호출하는 경우 이전 인터페이스에서는 iterator 객체를 IEnumerator 참조로 가져옵니다. 이를 통해 MoveNext()를 호출하고 Current 객체를 가져올 수 있습니다.
  • foreach : 어떻게 작동하는지 알 필요가 없다는 점에서 C# 구조/외관입니다. 내부적으로 반복기를 가져오고 각 항목 (foreach 블록의 내용)을 사용하여 수행하려는 작업에 집중할 수있는 올바른 방법을 호출합니다. 대부분의 경우, 자신 만의 타입이나 커스텀 반복을 구현하지 않는 한 foreach가 필요하다.이 경우 처음 2 개의 인터페이스를 알아야한다. 당신이하지 가있는 IEnumerator를 구현하는을 수행하고 foreach는 사용하는 그 varients 염두에
+0

Gishu에게 감사드립니다. 또한이 링크는 매우 유용하다고 생각합니다. http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering

6

베어 - IIRC, 그것은 필요로하는 모든이 반환하는 MoveNext는() 메소드를 가진 개체를 반환하는 GetEnumerator() 방법입니다 bool 및 객체를 반환하는 Current 속성 IEnumerator와 IEnumerable은 사용할 필요가 없지만 일반적으로 그렇게하는 것이 좋습니다. 자세한 내용은 here을 참조하십시오.

+0

이상한 오래 된 짐승입니다. 그냥 두 가지 방법을 구현하십시오. 그 일을하는 것의 큰 문제는 타입 시스템이 그 열거 형을 알지 못한다는 것입니다. 그래서 여러분은 Linq를 객체와 함께 사용하는 것이 어려울 것이라고 생각합니다. –

+3

예, 이상합니다. 이 기능을 지원하는 이유는 C# 1.0에 정수 컬렉션을 작성하고 boxing하지 않고 열거 할 수 있기 때문입니다. 이제 IE 을 사용 했으므로 더 이상 "패턴"접근이 필요하지 않습니다. –

+1

@Eric Lippert :이 기능에는 또 다른 이점이 있습니다. GetEnumerator 메서드가 구조체를 반환하는 클래스에는 클래스를 반환하는 IEnumerable.GetEnumerator 메서드가 있어야한다고 제안하지만 구조체 열거 자용 힙 할당을 피할 수 있습니다. – supercat