При реализации соственных методов MyWhere и MyTake не работает с условием while(true), работает только если ставить ограничение в цикл

//Доработать пример , реализовав собственные экстеншен методы MyWhere и MyTake. При реализации нельзя использовать yiled и коллекции. Только кастомные итераторы.

public static IEnumerable<int> GetEnumaration()

    {
        int i = 0;
        while (true)
        {
            yield return i++;
        }
    }

    public static IEnumerable<int> MyWhere(this IEnumerable<int> enumerator, Func<int, bool> predicate)
    {
        // return enumerator.Where(predicate);

        int[] array = enumerator.ToArray();

        int whereSize = 0;

        for (int i = 0; i < array.Length; i++)
        {
            if (predicate(array[i]))
            {
                whereSize++;
            }
        }

        int[] result = new int[whereSize];
        int j = 0;
        for (int i = 0; i < array.Length; i++)
        {
            if (predicate(array[i]))
            {
                result[j] = array[i];
                j++;
            }
        }

        return result.AsEnumerable();
    }

    public static IEnumerable<int> MyTake(this IEnumerable<int> enumerator, int count)
    {
        // return enumerator.Take(count);

        int[] array = enumerator.ToArray();
        int[] result = new int[count];

        for (int i = 0; i < count; i++)
        {
            result[i] = array[i];
        }

        return result.AsEnumerable();
    }

    public static void Main()
    {
        foreach (var item in GetEnumaration().Where(x => x % 2 == 0).Take(5))
        {
            Console.WriteLine(item);
        }
        Console.WriteLine("------------");

        foreach (var item in GetEnumaration().MyWhere(x => x % 2 == 0).MyTake(5))
        {
            Console.WriteLine(item);
        }
        Console.ReadLine();
    }

Ответы (1 шт):

Автор решения: tym32167

Вы упускаете смысл ленивых операций. А смысл их в том, чтобы проходить только по той части перечисления, что интересна конечному юзеру.

Вот как пример, ваш бесконечный цикл. Я добавил вывод в консоль, чтобы было понятно что происходит

public static IEnumerable<int> GetEnumaration()
{
    int i = 0;
    while (true)
    {
        Console.WriteLine($"GetEnumaration - {i}");
        yield return i++;
    }
}

А теперь полгядим на MyWhere - это операция фильтрации и она будет применяться также лениво

public static IEnumerable<int> MyWhere(this IEnumerable<int> source, Predicate<int> predicate)
{
    foreach (var item in source)
    {
        if (predicate(item)) yield return item;
    }
}

Для MyTake все тоже просто - мы проходим только по нужным нам элементам. То есть нет разона читать 100 элементов из перечисления, если нам надо только 3

public static IEnumerable<int> MyTake(this IEnumerable<int> source, int count)
{       
    if (count != 0)
    {
        int cnt = 0;
        foreach (var item in source)
        {
            yield return item;
            cnt++;
            if (cnt >= count) break;
        }
    }
}

Проверка будет простой

foreach (var item in GetEnumaration().MyWhere(x => x % 3 == 0).MyTake(3))
{
    Console.WriteLine(item);
}

Вывод

GetEnumaration - 0
0
GetEnumaration - 1
GetEnumaration - 2
GetEnumaration - 3
3
GetEnumaration - 4
GetEnumaration - 5
GetEnumaration - 6
6

Как видите, мы читали только те элементы из бесконечного цикла, которые нам интересны и не более.

Ваш же вызов .ToArray() пытается читать всю последовательность до конца, а у неё нет конца, там же while(true) стоит. Мой пример читает только до того момента, пока ему следует читать - как только порция нужных данных получена, больше ничего читать не надо из бесконечной последовательности.

→ Ссылка