Looking for c# Keywords? Try Ask4Keywords

C# Language Ленивый пример оценки: номера Фибоначчи


пример

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics; // also add reference to System.Numberics

namespace ConsoleApplication33
{
    class Program
    {
        private static IEnumerable<BigInteger> Fibonacci()
        {
            BigInteger prev = 0;
            BigInteger current = 1;
            while (true)
            {
                yield return current;
                var next = prev + current;
                prev = current;
                current = next;
            }
        }

        static void Main()
        {
            // print Fibonacci numbers from 10001 to 10010
            var numbers = Fibonacci().Skip(10000).Take(10).ToArray();
            Console.WriteLine(string.Join(Environment.NewLine, numbers));
        }
    }
}

Как это работает под капотом (я рекомендую декомпилировать полученный файл .exe в инструменте IL Disaambler):

  1. Компилятор C # генерирует класс, реализующий IEnumerable<BigInteger> и IEnumerator<BigInteger> ( <Fibonacci>d__0 in ildasm).
  2. Этот класс реализует конечный автомат. Состояние состоит из текущей позиции в методе и значениях локальных переменных.
  3. Самый интересный код - в методе bool IEnumerator.MoveNext() . В основном, что MoveNext() делает:
    • Восстанавливает текущее состояние. Переменные типа prev и current становятся полями в нашем классе ( <current>5__2 и <prev>5__1 in ildasm). В нашем методе мы имеем две позиции ( <>1__state ): сначала в открывающей фигурной скобке, второй - при yield return .
    • Выполняет код до следующего yield return yield break или yield break / } .
    • Для yield return результата yield return значение сохраняется, поэтому Current свойство может вернуть его. true возвращается. В этот момент текущее состояние сохраняется снова для следующего вызова MoveNext .
    • Для метода yield break / } метод возвращает false итерация выполняется.

Также обратите внимание, что 10001-е число составляет 468 байт. State machine сохраняет только current и prev переменные как поля. Хотя если мы хотим сохранить все числа в последовательности от первой до 10000-й, объем потребляемой памяти будет превышать 4 мегабайта. Такая ленивая оценка, если она правильно используется, в некоторых случаях может уменьшить объем памяти.