Ответ
В подавляющем большинстве сценариев цикл foreach будет иметь немного более высокую производительность, чем эквивалентный LINQ-запрос, из-за отсутствия накладных расходов на вызовы делегатов, создание итераторов и дополнительные проверки.
Сравнение на примере:
// LINQ (читаемо, но с накладными расходами)
var evenNumbersSum = numbers.Where(n => n % 2 == 0).Sum();
// Цикл foreach (обычно быстрее)
int evenNumbersSum = 0;
foreach (var number in numbers)
{
if (number % 2 == 0)
evenNumbersSum += number;
}
Когда что использовать:
-
Выбирайте LINQ для:
- Повышения читаемости и выразительности кода.
- Сложных операций (группировка, соединения, сортировка).
- Работы с
IQueryable<T>(запросы к БД, где LINQ транслируется в SQL).
-
Выбирайте цикл
for/foreachдля:- Критичных к производительности участков кода ("горячих путей"), доказанных профилированием.
- Очень простых операций над коллекциями.
- Работы с
Span<T>илиArray, где важен контроль над памятью.
Вывод: Начинайте с чистого и читаемого LINQ. Оптимизируйте конкретные участки до циклов только после того, как профилировщик (например, BenchmarkDotNet) покажет, что это даст значимый прирост производительности для вашего конкретного случая. Разница часто пренебрежимо мала для типичного бизнес-логического кода.
Ответ 18+ 🔞
Давай разберёмся с этим вопросом, как есть, без соплей и лишней философии.
Вот смотри, если гнаться за чистой скоростью, как угорелый, то обычный foreach почти всегда обгонит LINQ. Почему? Да потому что LINQ — это, по сути, красивая обёртка. Там под капотом те же итераторы, делегаты, куча проверок... Это как ехать на работу на такси: удобно, но своя машина всё-таки быстрее и дешевле, если не стоять в пробках.
Сравни, как это выглядит:
// LINQ — красиво, стильно, но с накруткой
var evenNumbersSum = numbers.Where(n => n % 2 == 0).Sum();
// Цикл foreach — прямолинейно, без фокусов, зато шустро
int evenNumbersSum = 0;
foreach (var number in numbers)
{
if (number % 2 == 0)
evenNumbersSum += number;
}
Второй вариант — это как взять и дойти пешком, не вызывая лифт на каждом этаже. Меньше движений — меньше времени.
Так когда же что брать?
-
Хватай LINQ, если:
- Хочешь, чтобы код читался как книга, а не как шифровка от сумасшедшего.
- Делаешь что-то мудрёное: соединяешь таблицы, группируешь, сортируешь — там LINQ просто царь и бог.
- Работаешь с базой данных через
IQueryable<T>. Тут без вариантов — LINQ твой единственный счастливый билет, потому что он в SQL превратится.
-
Врубай обычный цикл, если:
- У тебя в коде есть место, которое профилировщик показал красным — «горячая точка», где каждый микросекунд на счету. Вот там да, выжимай соки.
- Операция проще некуда: пробежаться, посчитать, отфильтровать по одному условию.
- Ковыряешься с
Span<T>или массивами, где нужно ручное управление памятью, как в старые добрые времена.
Итог, чтобы не было мути: Пиши сначала на LINQ. Сделай код понятным и рабочим. А потом, если всё тормозит и скрипит, бери профилировщик (типа BenchmarkDotNet), находи конкретное узкое место и только тогда переписывай его на цикл. В 95% случаев разница будет настолько мизерная, что проще на неё забить, чем читать потом свой же спагетти-код из циклов и пытаться понять, что же ты, сука, имел в виду полгода назад.