2011-10-11 8 views
4

어, 아주 확실하지 않은 방법으로 표현이 있지만 열거의 첫 번째 항목의 복사본을 반환 나타납니다 ..왜 감안할 때 Enumerable.First()

를 호출 않는 IEnumerable을 세 개의 인스턴스를 포함, 수율 반환을 사용하여 만든 클래스의 .First() 호출이 첫 번째 인스턴스의 '복사본'을 반환하는 것처럼 보이는 이유는 무엇입니까?

다음 코드를 참조하십시오.

public class Thing 
    { 
     public bool Updated { get; set; } 

     public string Name { get; private set; } 

     public Thing(string name) 
     { 
      Name = name; 
     } 

     public override string ToString() 
     { 
      return string.Format("{0} updated {1} {2}", Name, Updated, GetHashCode()); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("IEnumerable<Thing>"); 
      var enumerableThings = GetThings(); 
      var firstThing = enumerableThings.First(); 
      firstThing.Updated = true; 
      Console.WriteLine("Updated {0}", firstThing); 
      foreach (var t in enumerableThings) 
       Console.WriteLine(t); 

      Console.WriteLine("IList<Thing>"); 
      var thingList = GetThings().ToList(); 
      var thing1 = thingList.First(); 
      thing1.Updated = true; 
      Console.WriteLine("Updated {0}", thing1); 
      foreach (var t in thingList) 
       Console.WriteLine(t); 

      Console.ReadLine(); 
     } 

     private static IEnumerable<Thing> GetThings() 
     { 
      for (int i = 1; i <= 3; i++) 
      { 
       yield return new Thing(string.Format("thing {0}", i)); 
      } 
     } 
    } 
} 

이렇게하면 다음과 같은 결과가 출력됩니다.

IEnumerable<Thing> 
Updated thing 1 updated True 37121646 
thing 1 updated False 45592480 
thing 2 updated False 57352375 
thing 3 updated False 2637164 
IList<Thing> 
Updated thing 1 updated True 41014879 
thing 1 updated True 41014879 
thing 2 updated False 3888474 
thing 3 updated False 25209742 

하지만 난 IList의와 IEnmerable이 같은 동일 출력 행동을 기대 ...

IEnumerable<Thing> 
Updated thing 1 updated True 45592480 
thing 1 updated False 45592480 
thing 2 updated False 57352375 
thing 3 updated False 2637164 
IList<Thing> 
Updated thing 1 updated True 41014879 
thing 1 updated True 41014879 
thing 2 updated False 3888474 
thing 3 updated False 25209742 

내가 무엇을 놓치고?!

답변

3

GetThings이 아니며는 실제 수집품입니다. 그것은 컬렉션을 "요리하는"방법 인 "요리법"을 반환하고, 당신이 그것을 반복하도록 요청할 때만 "조리 된"것입니다. 그것은 yield의 마술입니다.

그래서 .First()을 호출 할 때마다 루프가 실행되고 실제로 새 인스턴스가 만들어집니다.

+1

Dan Bryant 대답은 정확한 용어로 기술 부분을 더 잘 다룹니다.:) –

+0

물론, 이런, 고마워. - 고마워. – sackoverflow

1

'yield return'에 의해 생성 된 IEnumerable은 열거 된 값만 생성하고 첫 번째 경우에는 두 번 열거합니다. 두 번째로 열거 할 때 실제로 완전히 별도의 물건 세트를 만듭니다.

수익률 반환은 기본적으로 열거 될 때 열거 된 결과를 산출하기 위해 코드를 통해 진행되는 상태 시스템을 생성하는 코드의 바로 가기입니다. 결과 자체는 List에 저장하는 등의 작업을 수행 할 때까지 어디에도 저장되지 않습니다.

0

반복자 (yield return을 사용하는 모든 방법)는 반복 할 때 지연 평가됩니다. 즉, 메서드 본문을 호출 할 때 실행되지 않습니다. 결과는 foreach 또는 일부 호출을 통해 IEnumerable<T> 결과를 열거 할 때만 실행됩니다. 그리고 각각 을 실행합니다. 시간이 foreach입니다.

.First()IEnumerable<T>을 열거해야하므로 (요소를 가져 오는 유일한 방법이므로) .First()을 호출 할 때마다 메서드 본문이 다시 실행됩니다.

보통 해결책은 준비가되었을 때 반복기를 강제 실행하여 .ToList() 또는 .ToArray()으로 호출하는 것입니다. 그러면 List<T> 또는 배열을 반복 할 때 더 이상 변경되지 않습니다.

0

IEnumerable 구현 (GetThings)은 반복 할 때마다 새 항목을 반환합니다. 따라서 IEnumerable의 foreach에서는 각각의 Thing이 새로 생성됩니다. IEnumerable에 ToList를 추가하면 목록에 IEnumerable에서 생성 된 "항목"이 목록에 저장된다는 의미에서 IEnumerable에서 가져온 각 항목의 "복사본"이 실제로 포함됩니다. "사물"목록에 대한 후속 반복은 항상 "사물"의 동일한 세트를 산출합니다. IEnumerable에 대한 후속 반복은 항상 새로운 "사물"집합을 산출합니다.