Если метод GetEnumerator все еще будет идентифицированным, когда класс не реализует Ienumerable

StackOverflow https://stackoverflow.com/questions/4194900

Вопрос

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

Общий консенсус заключается в том, что нет ничего, что реализует Ienumerable, не должно быть идентифицированным. Но .NET поддерживает компиляцию времени, набираясь утки с заявлением Foreach. Любой объект, который обеспечивает метод getEnumerator () ienumerator (), может использоваться внутри оператора Foreach.

Так должен ли метод GetEnumerator быть идентифицированным или это, когда он реализует Ienumerable?

Редактировать (добавленный контекст)

Чтобы обойти этот контекст, то, что я предлагаю, - это то, что когда итерация в очереди каждый элемент находится в результате. Кроме того, любые новые объекты, выдвинутые в очередь после того, как вызов GetEnumerator все еще будет повторен.

Это было полезно?

Решение

Это не тип Что идентификационно - это даже не имеет большого смысла; ты май подразумевается, но это не ясно. Это GetEnumerator Сам метод, который обычно идентифицирован.

Пока я бы сказал, что это обычно Случай, я могу представить особые случаи, когда имеет смысл иметь неэпозицию GetEnumerator метод Например, может быть, что у вас есть данные, которые можно прочитать только один раз (потому что он потокосится с веб -сервера, который больше не будет обслуживать тот же запрос или что -то в этом роде). В этом случае, GetEnumerator Придется эффективно аннулировать источник данных, чтобы будущие вызовы сделали исключение.

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

Другие советы

Это обсуждение старое, и, насколько мне известно, нет общего мнения.

Пожалуйста, не путайте концепцию (время выполнения) утка с злоупотреблением поддержанием компилятора foreach Чтобы поддержать желаемую семантику.

Еще одна концепция, которую вы, кажется, запутаете, - это идентичность против неизменности. Согласно вашей формулировке, вы пытаетесь описать второе, что означает, что объект, предоставляющий перечисление, изменяется во время перечисления. Идепотентность, с другой стороны, означает ваш перечисление, когда вызов дважды вызовут, даст одинаковые результаты.

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

  • Перечисление по сравнению с случайным образом изменяющими данные (то есть генератор случайных чисел, потоки датчиков)
  • Перечисление над общим состоянием (например, файлы, базы данных, потоки и т. Д.)

С другой стороны, это только учитывает операции «источник». Если вы внедряете операции фильтра или преобразования с помощью перечислений, вам всегда следует стараться сделать их идентифицированными.

Кажется, вам нужен класс очередей, из которого вы можете остановить все предметы в хорошей линии.

Нет ничего плохого в этой идее как таковой; Я бы просто поставил под сомнение ваши предпочтения конкретно использовать GetEnumerator Чтобы достичь того, что вам нужно.

Почему бы просто не написать метод, который является более явным с точки зрения того, что он делает? Например, DequeueAll, или что -то в этом роде.

Пример:

// Just a simplistic example. Not the way I'd actually write it.
class CustomQueue<T> : Queue<T>
{
    public IEnumerable<T> DequeueAll()
    {
        while (Count > 0)
        {
            yield return Dequeue();
        }
    }
}

(Обратите внимание, что вышеупомянутое может быть даже Метод расширения, если это буквально Только функциональность, которую вы хотели бы сверх того, что уже предоставлено Queue<T>.)

Таким образом, вы все равно могли бы получить «чистый» код, я подозреваю, что вам нужно, без (потенциальной) путаницы неампотента GetEnumerator:

// Pretty clean, right?
foreach (T item in queue.DequeueAll())
{
    Console.WriteLine(item);
}

Я бы предположил, что использование Foreach в коллекции не должно изменить ее, если не подразумевается название типа коллекции. Проблема, на мой взгляд, будет то, что должно быть возвращено, если выполняется метод, чтобы потреблять коллекцию во что -то перечисленное (например, чтобы «разрешить« для каждого foo в mything.dequeAseNum »). Если DequeUeaseNum вернется на подъеме, то кто-то может рассчитывать на то, что он сойдет с рук с «Dim MyIenumerable как iEnumerable = mything.dequeAseNum», а затем использовать MyIenumerable в двух непересеченных за свои петли. Если DequeUeaseNum возвращает тип перечисления, то было бы немного яснее, что его возвращение следует перечислять только один раз. Безусловно, существование неявного набора в диалектах C# и VB.NET делает немного более вероятной, что кто -то может назначить функцию, возвращаясь к переменной, когда они не должны, но я не знаю, как это предотвратить.

Кстати, существует ряд обстоятельств, когда было бы полезно предотвратить хранение ссылки на класс в переменной; Есть ли способ объявить класс таким образом, чтобы внешний код мог использовать выражения этого типа класса, но не может объявить его переменные?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top