Инициализация счетчиков - PullRequest
0 голосов
/ 23 мая 2018

Итак, я медленно читаю свой трудовой журнал и перешел к разделу по счетчикам.Во время которого он дает пример кода

public class GameMoves
{
    private IEnumerator _cross;
    private IEnumerator _circle;

    private int i;

    public GameMoves()
    {            
        _cross = Cross();
        _circle = Circle();
        i = I();
    }
    private int _move = 0;
    const int MaxMoves = 9;

    public int I()
    {
        Console.WriteLine("Test");
        return (1);
    }

    public IEnumerator Cross()
    {
        while (true)
        {
            WriteLine($"Cross, move {_move}");
            if (++_move >= MaxMoves)
            {
                yield break;
            }
            yield return _circle;
        }
    }

    public IEnumerator Circle()
    {
        while (true)
        {
            WriteLine($"Circle, move {_move}");
            if (++_move >= MaxMoves)
            {
                yield break;
            }
            yield return _cross;
        }
    }
}

Я запускаю это из метода main и создаю новый экземпляр этого класса.Когда конструктор запускает _cross = Cross();, я ожидал, что он будет работать аналогично i = I();, т.е. будет проходить через класс и принимать возвращаемое значение.Когда я прохожу программу, она вообще не активирует класс Cross(), вместо этого эта строка создает перечислитель со значением null.Просто интересно, может ли кто-нибудь объяснить, что делает этот шаг.Спасибо

1 Ответ

0 голосов
/ 23 мая 2018

Весь смысл итераторов - именно то, что вы видите.Предполагается, что итератор откладывает выполнение до фактического использования результатов.В вашем коде метод I не является итератором, поэтому его тело выполняется до конца при вызове.Метод Cross является итератором, поэтому его тело не будет выполнено, пока вы не используете результат.

Например, если бы вы использовали цикл foreach для перечисления _cross, вы бы увидели, чтокаждая итерация цикла приведет к попаданию ключевого слова yield в методе Cross.После нажатия yield break метод завершится, и ваш цикл завершится.

В качестве примера того, почему это хорошо, давайте сравним метод File.ReadAllLines и метод File.ReadLines.Первый появился с .NET 1.0, а второй - гораздо позднее.Метод ReadAllLines читает весь файл и разбивает его на строки, а затем возвращает массив, содержащий эти строки.Это означает, что вы не можете начать обработку файла, пока все его содержимое не будет прочитано.Это также означает, что вы должны прочитать все содержимое, даже если оно вам не нужно.Например, если миллион строк и вы хотите, чтобы первая содержала определенное слово, вам пришлось бы читать каждую строку, даже если вы нашли слово в десятой строке.

Для сравнения, ReadLines метод итератор.Он не начинает чтение файла до тех пор, пока вам действительно не нужны данные, и он считывает данные только по мере необходимости.Это означает, что вы можете обрабатывать данные по мере их чтения, а не ждать, пока они все будут прочитаны, чтобы начать обработку.Это также означает, что вам не нужно читать больше данных, чем требуется, например, если вы начнете искать слово и найдете его в десятой строке, оставшиеся 999 990 строк не будут прочитаны.

...