Отправка элементов последовательности LINQ в метод, который возвращает void

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

  •  19-09-2019
  •  | 
  •  

Вопрос

Часто, когда я имею дело с последовательностями 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 вернет последовательность логических значений — я просто проигнорирую эту последовательность.Однако это кажется немного нубским и глупым.Есть ли какой-нибудь элегантный способ сделать это?Или я просто неправильно применяю LINQ?

Спасибо.

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

Решение

Прежде всего, ваш текущий код не будет работать.
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;
}

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

По общему мнению, LINQ предназначен для запроса и выбора...пока вы используете традиционные итеративные методы для циклов и итераций.

Ненавижу это говорить, но вы бы использовали традиционный цикл foreach, потому что хотите, чтобы ваши запросы linq выполнялись, и вы перебираете полученный IEnumerable.Это помогает улучшить читаемость кода, и я признаю, что LINQ вызывает привыкание.Вы хотите делать все, используя Lambdas и отложенное выполнение, но цикл следует оставить на усмотрение традиционных методов цикла C#.Это определенно поможет справиться с побочными эффектами.

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