2010-03-15 4 views
18

가능한 중복 :
How does foreach work when looping through function results?foreach 루프를 반복 할 때마다 함수가 호출됩니까?

나는 다음과 같은 기능이있는 경우 -()는 foreach 루프의 각 반복에 대해 불려가는 ReturnParts를, 또는이 한 번에 바로 전화를받을 것 ?

private void PrintParts() 
{ 
    foreach(string part in ReturnParts()) 
    { 
     // Do Something or other. 
    } 
} 

private string[] ReturnParts() 
{ 
    // Build up and return an array. 
} 
+1

중복 : http://stackoverflow.com/questions/1632810/how-does-foreach-work-when-looping-through-function-results –

답변

25

한 번만 호출됩니다.

P. 여러 번 호출하면 거의 이해가되지 않습니다. 매번 결과가 다를 것으로 예상되면 매번 다시 호출해야합니다. 그리고 지속적으로 변화하는 세트를 반복하는 방법은 무엇입니까?

9

한 번만 호출됩니다.

The foreach loop is equivalent to the following code:

IEnumerable<string> enumerator = (collection).GetEnumerator(); 
try { 
    while (enumerator.MoveNext()) { 
     string part = (string)enumerator.Current; 

     // Do Something or other. 

    } 
} finally { 
    IDisposable disposable = enumerator as System.IDisposable; 
    if (disposable != null) disposable.Dispose(); 
} 
17

당신은 경우 각각의 반복에 대한 mutliple 번 다음 예는 않습니다 명중 기능의 "ReturnParts을"중단 점을 배치하여이 자신을 확인할 수 있습니다.

+0

는 제안을 주셔서 감사합니다. 이것은 자신의 질문에 대한 답변을 찾는 좋은 방법입니다. –

6

for, foreach, while, goto의 차이점을 몇 주 전에 궁금하게 생각하면서이 테스트 코드를 작성했습니다. 모든 메소드는 동일한 IL (foreach 버전의 다른 변수 이름)로 컴파일됩니다. 디버그 모드에서 일부 NOP 문은 다른 위치에 있습니다. 에릭의 코멘트 @ 당

static void @for<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     for (; e.MoveNext();) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @foreach<T>(IEnumerable<T> input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
     while (e.MoveNext()) 
     { 
      item = e.Current; 
      Console.WriteLine(item); 
     } 
} 
static void @goto<T>(IEnumerable<T> input) 
{ 
    T item; 
    using (var e = input.GetEnumerator()) 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
} 
static void @gotoTry<T>(IEnumerable<T> input) 
{ 
    T item; 
    var e = input.GetEnumerator(); 
    try 
    { 
     goto check; 
    top: 
     item = e.Current; 
     Console.WriteLine(item); 
    check: 
     if (e.MoveNext()) 
      goto top; 
    } 
    finally 
    { 
     if (e != null) 
      e.Dispose(); 
    } 
} 

...

나는 일반적인 배열 for, while, '고토'와 foreach을 확장했다. 이제 for each 문은 배열에 대한 인덱서를 사용합니다. 객체 배열과 문자열도 비슷한 방식으로 확장됩니다. Console.WriteLine 및 Strings에 대한 메서드 호출이 T itemT[] copy...char itemstring copy...으로 각각 대체하기 전에 발생하는 복싱을 제거합니다. 일회용 열거자를 더 이상 사용하지 않기 때문에 중요 섹션을 더 이상 필요하지 않습니다.

static void @for<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    for (int i = 0; i < copy.Length; i++) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
    } 
} 
static void @foreach<T>(T[] input) 
{ 
    foreach (var item in input) 
     Console.WriteLine(item); 
} 
static void @while<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    while (i < copy.Length) 
    { 
     item = copy[i]; 
     Console.WriteLine(item); 
     i++; 
    } 
} 
static void @goto<T>(T[] input) 
{ 
    T item; 
    T[] copy = input; 
    int i = 0; 
    goto check; 
top: 
    item = copy[i]; 
    Console.WriteLine(item); 
    i++; 
check: 
    if (i < copy.Length) 
     goto top; 
} 
+0

@gotoTry는 컴파일 된 IL을 표시하지 않고 생각할 수있는 가장 확장 된 버전입니다. –

+2

멋지게 완료되었습니다. 물론 IEnumerable 을 구현하는 경우에만 확장됩니다. foreach는 배열과 문자열에 대해 다른 코드를 생성합니다. –

+0

@ 에릭 : 피드 백에 감사드립니다. 나는 가장 일반적인 버전으로 가고 있었지만 나중에 더 연장 할 수 있습니다. (나는 주로 goto 버전에 관심이 많았는데, 대부분이 여전히 "악"이라고 생각한다.) –

관련 문제