Эрик Липперт советует не писать такие циклы как выражения.
Используйте выражения запроса, только если код не имеет побочных эффектов и выдает значение.
В этом случае вы циклически повторяете оператор, который имеет побочный эффект для консоли и не возвращает значений. Таким образом, цикл foreach более понятен и разработан специально для этой цели.
С другой стороны, действие (которое может иметь побочные эффекты) может рассматриваться как чистое значение до его выполнения . Итак, вот список номеров:
List<int> numbers = Enumerable.Range(1, 10).ToList();
Отсюда составляем список действий:
List<Action> actions = numbers.Select(n => Console.WriteLine(n)).ToList();
Хотя мы имеем дело с действиями, которые имеют побочные эффекты, на самом деле мы их вообще не выполняем, поэтому любые дальнейшие манипуляции с содержимым этого списка не имеют побочных эффектов. Наконец, когда у нас есть список, который нам нужен, мы можем использовать forloop для его выполнения:
foreach (var a in actions)
a();
И это такой простой шаблон, можно утверждать, что метод расширения RunAll
на IEnumerable<Action>
не будет плохой вещью. Действительно, в платформу .NET встроена эта концепция: многоадресный делегат - это единственная вещь, которую вы можете вызвать, которая выполняет группу делегатов в списке. В наиболее распространенных случаях использования (событиях) эти делегаты имеют побочные эффекты.