Это плохая практика внедрения бесконечных перечислителей и перечислимых элементов? - PullRequest
0 голосов
/ 21 октября 2018

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

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?Однако это лишило бы меня возможности использовать синтаксический сахар C #, например yield и foreach.

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

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

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

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 Interface

0 голосов
/ 21 октября 2018

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

...