Раннее выполнение IEnumerable - PullRequest
0 голосов
/ 18 февраля 2019

Итак, у меня есть два метода, оба выполняющих итерацию по коллекции IEnumerable.

    public static IEnumerable<int> GetRange(int start, int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException(nameof(count));

        var end = start + count;

        for (int value = start; value < end; value++)
        {
            yield return value;
        }
    }


    public static IEnumerable<int> GetRangeFunction(int start, int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException(nameof(count));

        var end = start + count;
        return RangeEnumeration();

        //Using local function
        IEnumerable<int> RangeEnumeration()
        {
            for (var value = start; value < end; value++)
            {
                yield return value;
            }
        }
    }

Недавно я узнал, что метод, возвращающий IEnumerable, не будет выполняться, пока не будет перечислен.

Итак, ясоздал два блока кода для вызова каждого метода

Вызов GetRange

var iterator = GetRange(0, 10); // This does not start the execution of `GetRange` method. Instead, it waits till any item is requested
foreach(var item in iterator) //Now the GetRange method is called
{

}

GetRangeFunction

Но, в случаеиз GetRangeFunction, метод вызывается сразу при создании итератора.

var iterator = GetRangeFunction(0, 5);

Почему это поведение?Я думал, что GetRangeFunction также не выполнится, пока не будет запрошен элемент.

РЕДАКТИРОВАТЬ

Мой вопрос плохо сформулирован, позвольте мне попытаться объяснить его одинбольше времени.

Оба перечислителя возвращают элементы через yield один за другим.Но в случае GetRange оператор (not even checking count is less than zero) не выполняется до тех пор, пока над перечислителем не будет выполнена какая-либо операция.Но в случае GetRangeFunction проверка условия выполняется при вызове метода для создания итератора.

1 Ответ

0 голосов
/ 18 февраля 2019

Согласно MSDN , локальная функция может немедленно разрешать появление исключений.Например, рассмотрим следующий код.

        static void Main()
        {            
            IEnumerable<int> ienum = GetNumber(50, 110);
            //below line will not execute if use GetNumberByLocalMethod
            Console.WriteLine("Retrieved enumerator...");

            foreach (var i in ienum)
            {
                Console.Write($"{i} ");
            }
        }

        public static IEnumerable<int> GetNumberByLocalMethod(int start, int end)
        {
            throw new Exception("deliberately exception");
            return InnerGetNumberByLocalMethod();
            IEnumerable<int> InnerGetNumberByLocalMethod()
            {
                for (int i = start; i <= end; i++)
                {                    
                        yield return i;
                }
            }
        }

        public static IEnumerable<int> GetNumber(int start, int end)
        {
            throw new Exception("deliberately exception");

            for (int i = start; i <= end; i++)
            {                
                    yield return i;
            }
        }

Чтобы убедиться, что версия локального метода может быстро получить исключение, версия GetNumberByLocalMethod будет выполнена немедленно и не будет ждать до первой итерации.

...