Если вы пишете код, который будет посещать каждый узел (как с деревом), возможно, есть итераторы итератора для каждой ветви и выполнить yield return
на листовых узлах. Этот подход будет работать, и он очень прост, но имеет серьезный недостаток, что очень легко получить код, который будет очень читабельным, но выполняется очень медленно. Некоторые другие вопросы и ответы на этом сайте помогут понять, как эффективно перемещаться по деревьям внутри итератора.
Если «дерево» было всего лишь примером, и у вас действительно есть класс, который предоставляет процедуру для вызова некоторого делегата на каждом узле (аналогично List.ForEach()
), но не выставляет IEnumerable
, вы можете быть в состоянии чтобы использовать первый, чтобы создать List
, который вы могли бы затем повторить. Используйте что-то вроде var myList = new List<someThing>(); myCollection.ForEach((x) => myList.Add(x));
, и тогда вы сможете перечислить myList
.
Если этого недостаточно, поскольку объекты, которые были добавлены в список, могут быть недействительны по истечении времени, указанного в списке, в редких случаях возможно использовать несколько потоков для выполнения необходимого. Например, если у вас есть две сортированные коллекции, метод ForEach
подготавливает каждый элемент к использованию, выполняет ли указанное действие и затем очищает каждый элемент перед тем, как перейти к следующему, и если вам нужно чередоваться с действиями по элементам из двух независимых коллекций, можно было бы выполнять итерацию коллекций в отдельных потоках и использовать примитивы синхронизации, чтобы каждый поток подождал по мере необходимости для другого.
Обратите внимание, что коллекции, которые только выставляют себя с помощью метода ForEach
склонны ограничивать доступ во время выполнения такой ForEach
(если такое ограничение не было необходимости, они, вероятно, реализовать IEnumerable
). Возможно, что «действие предмета», вызванное одним ForEach
, выполнить еще один ForEach
в том же сборнике в том же потоке, поскольку последний ForEach
должен был завершиться до того, как предыдущий мог возобновиться. Однако, хотя один ForEach
работает, попытка вызвать ForEach
во втором потоке, вероятно, либо сработает, либо дождитесь завершения первой операции. Если первый ForEach
ожидал какого-либо действия вторым, это приведет к взаимоблокировке. Из-за этого сценарии, в которых многопоточность будут работать лучше, чем просто создание List
, редки. Тем не менее, есть несколько случаев, когда это может быть полезно (например, вышеупомянутая операция «застежка-молния» в независимых коллекциях).
Не уверен, что вы просите ... вы хотите, чтобы класс/шаблон автоматически создавал ленивый 'IEnumerable' для иерархии объектов, учитывая подходящий метод посетителя? (Если это так, я подозреваю, что ответ «нет», если объект также не поддерживает перечисление * flat *, которое пересекает только «детей» данного объекта). –
@ KonradRudolph да. Мне не нужен класс/паттерн, скорее, как функция языка или концепция. Я чувствую, что продолжения могут быть связаны, но я недостаточно знаком с ними. –
Я думаю, что это свойство структуры, а не какой-либо функции языка. Чистое (как в большинстве абстрактных) представление этого, что я знаю, - это Складное слово Хаскелла (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html), см., В частности, foldMap , –