2016-12-21 3 views
1
static void Main() 
{ 
    DaysOfTheWeek days = new DaysOfTheWeek(); 

    foreach (string day in days) 
    { 
     Console.Write(day + " "); 
    } 

    // Output: Sun Mon Tue Wed Thu Fri Sat 
    Console.ReadKey(); 
} 

public class DaysOfTheWeek : IEnumerable 
{ 
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 

    public IEnumerator GetEnumerator() 
    { 
     for (int index = 0; index < days.Length; index++) 
     { 
      // Yield each day of the week. 
      yield return days[index]; 
     } 
    } 
} 

Что происходит в цикле foreach. Он вызывает функцию GetEnumerator, для каждой итерации или foreach заменяется функцией GetEnumerator? В этом случае сложность идет на O (n2)?Работа IEnumerator в C#

+3

Возможный дубликат [В C#, foreach чисто «синтаксический сахар»? Или есть что-то более глубокое об этом?] (Http://stackoverflow.com/questions/5816776/in-c-is-foreach-purely-a-syntactic-sugar-or-is-there-anything-deeper-about) –

+0

Я не понимаю, как это отвечает на вопрос @Janne –

ответ

2

Существует хороший Desription из yield return в этом блоге:

https://www.kenneth-truyers.net/2016/05/12/yield-return-in-c/

В основном это говорит, что

Каждая итерация цикла Еогеасп вызывает метод итератора. Когда будет достигнуто выражение return return, возвращается значение, а текущее местоположение в коде сохраняется. Выполнение перезапускается из этого места в следующий раз, когда вызывается функция итератора.

Поскольку местоположение сохраняется для следующего вызова, я считаю, что сложность должна быть O (n), а не O (n2).

4

yield return создает конечный автомат, который в основном возвращает значение, а затем ждет, пока вызывающий абонент (ваш первый foreach) запросит следующий элемент в перечислителе.

IEnumerable - это просто интерфейс, который описывает способ итерации по набору данных, IEnumerator - это интерфейс, который описывает, как вызвать итератор.

+0

Кажется, сложность идет на O (n2)? Не так ли? – Prabu

+0

Нет, почему это должно быть O (n2)? Просто O (n) будет делать. –

+0

Перечислитель списка/array использует int для указания на запрашиваемый элемент. Для каждого цикла в 'foreach' вызывается' MoveNext' и просто увеличивает указатель. Поиск в этих структурах O (1). Ссылка: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,1140 – Caramiriel

0

Нет, GetEnumerator не будет вызываться для каждой итерации. Если вы скомпилируете свой код в конфигурации выпуска и проверите сгенерированный код IL, вы получите такой код.

IEnumerator enumerator2 = days.GetEnumerator(); 
try 
{ 
    while (enumerator2.MoveNext()) 
    { 
     Console.Write((string)enumerator2.Current + " "); 
    } 
} 
finally 
{ 
    IDisposable disposable = enumerator2 as IDisposable; 
    if (disposable != null) 
    { 
     disposable.Dispose(); 
    } 
} 

Так в основном вы могли бы написать тот же самый код самостоятельно, Еогеасп это просто синтаксический сахар, чтобы помочь вам писать меньше кода.

Смежные вопросы