Является ли плохой практикой реализация бесконечных перечислителей и перечисляемых?

У меня есть следующий класс:

class CopyProvider<T> where T: IMyCloneable
{
    private readonly T _original;

    public CopyProvider(T original) => _original = original;

    public T Current { get; private set; }

    public bool MoveNext()
    {
        Current = _original.Clone();
        return true;
    }
}

Теперь мне интересно, было бы хорошей практикой объявить этот класс реализацией IEnumerator<T>. С синтаксической точки зрения CopyProvider соответствует требованиям, но будет ли это нарушением семантики IEnumerator?

В качестве альтернативы я также мог бы написать следующий метод:

IEnumerable<T> ProvideCopies<T>(T original) where T: IMyCloneable
{
    while(true)
        yield return original.Clone();
}

Это, действительно, было бы гораздо удобнее. Но снова я сталкиваюсь с тем же вопросом: не нарушит ли такое использование IEnumerable семантику интерфейса?

Или мне следует подумать о реализации отдельной структуры объекта с InfiniteEnumerator и/или InfiniteEnumerable? Однако это помешало бы мне использовать синтаксический сахар С#, такой как yield и foreach.

Я с нетерпением жду ваших рекомендаций.


person KnorxThieus    schedule 21.10.2018    source источник
comment
Почему/что именно будет нарушением интерфейса? Кроме того, InfiniteEnumerator не имеет для меня никакого смысла, с чего бы ему быть бесконечным?   -  person Camilo Terevinto    schedule 21.10.2018
comment
@CamiloTerevinto почему это должно быть бесконечно? - потому что IEnumerator.MoveNext() никогда не возвращает false. Законным использованием может быть перечислитель случайных значений из Как создать перечисление случайных значений?. Вы можете сделать что-то вроде random.GetRandomValues().TakeWhile(i => (some condition)). В любом случае, этот вопрос кажется мне в первую очередь мнением, или, может быть, дубликатом является ли бесконечное перечисление все еще «перечисляемым»?.   -  person dbc    schedule 21.10.2018
comment
Связанный: MVP- Отправлено: Расчет с бесконечными последовательностями в C# в MSDN; также заархивировано здесь: download.microsoft.com/download/5/4/B/   -  person dbc    schedule 22.10.2018


Ответы (2)


Если ваше перечисление никогда не перестанет давать результаты, было бы лучше потребовать от разработчика четко указать, какое максимальное количество будет сгенерировано, чтобы исключить риск бесконечного цикла, когда разработчик использует синтаксис for each с вашим перечисляемым . например

IEnumerable<T> ProvideCopies<T>(T original, int howMany) where T: IMyCloneable<T>
{
    return Enumerable.Range(1, howMany).Select(x => original.Clone());
}

или, если вы старая школа:

IEnumerable<T> ProvideCopies<T>(T original, int howMany) where T: IMyCloneable<T>
{
    for (var i = 0; i < howMany; i++)
        yield return original.Clone();
}

Таким образом, разработчик не обязан потреблять все перечисление и может остановиться в любой момент (т. е. вы по-прежнему уступаете по мере продвижения), но вы знаете, что это остановится в какой-то момент, вместо того, чтобы ввести возможность навсегда заблокировать ваш код в производстве из-за ошибки в коде.


Если вы действительно не можете сказать, сколько копий потребуется, и вам нужно продолжать генерировать копии, пока что-то еще не скажет вам остановиться, тогда IObservable<T> лучше подходит для этого сценария, так как он предназначен для "прослушивания" до тех пор, пока вы Dispose() не Это.

Интерфейс IObservable

person C. Augusto Proiete    schedule 21.10.2018

Да, я думаю, что это действительно плохая практика. Поток не сможет обрабатывать любые другие пути кода. А это сильно нагружает процессор.

person Vaibhav Gawali    schedule 21.10.2018
comment
Вопрос был не в том, плохо ли не останавливать/не прерывать перечисление счетной бесконечности ;-) (Также см. ссылки, приведенные в комментарии dbc к вопросу) - person ; 21.10.2018