Отправка элементов в последовательности LINQ методу, который возвращает void
Часто, когда я имею дело с последовательностями LINQ, я хочу отправить каждый элемент методу, возвращающему void, избегая цикла foreach. Однако я не нашел элегантный способ сделать это. Сегодня я написал следующий код:
private StreamWriter _sw;
private void streamToFile(List<ErrorEntry> errors)
{
if (_sw == null)
{
_sw = new StreamWriter(Path.Combine
(Path.GetDirectoryName(_targetDatabasePath), "errors.txt"));
}
Func<ErrorEntry, bool> writeSelector =
(e) => { _sw.WriteLine(getTabDelimititedLine(e)); return true; };
errors.Select(writeSelector);
_sw.Flush();
}
Как вы можете видеть, я пишу функцию лямбда, которая возвращает true, и я понимаю, что метод Select вернет последовательность логических значений - я просто проигнорирую эту последовательность. Однако, это кажется немного noobish и jank. Есть ли элегантный способ сделать это? Или я просто неправильно использую LINQ?
Спасибо.
Ответы
Ответ 1
Прежде всего, ваш текущий код не будет работать.
Select
и большинство других методов LINQ, используйте отложенное выполнение, что означает, что они фактически ничего не делают, пока вы не перечислите результаты.
В общем, вы никогда не должны использовать лямбда с побочными эффектами в запросе LINQ.
Чтобы ответить на ваш вопрос, вы должны использовать цикл foreach
.
Вы ищете метод расширения foreach
; Эрик Липперт объясняет, почему Microsoft не написала ни одного.
Если вы действительно этого захотите, вы можете написать один:
public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action) {
if (sequence == null) throw new ArgumentNullException("sequence");
if (action == null) throw new ArgumentNullException("action");
foreach(T item in sequence)
action(item);
}
//Return false to stop the loop
public static void ForEach<T>(this IEnumerable<T> sequence, Func<T, bool> action) {
if (sequence == null) throw new ArgumentNullException("sequence");
if (action == null) throw new ArgumentNullException("action");
foreach(T item in sequence)
if (!action(item))
return;
}
Ответ 2
Общий консенсус в том, что LINQ предназначен для запросов и выбора..., в то время как вы используете традиционные итерационные методы для циклирования и итерации.
Мне не нравится это говорить, но вы бы использовали традиционный цикл foreach, потому что вы хотите, чтобы ваши запросы linq выполнялись, и вы перебираете полученный IEnumerable. Это помогает с читабельностью кода, и я соглашусь, что LINQ вызывает привыкание. Вы хотите сделать все, используя Lambdas и отложенное выполнение, но цикл должен быть оставлен вашим традиционным методам циклирования С#. Это, безусловно, поможет с побочными эффектами.