Я видел, как некоторые программисты используют это:
foreach (var item in items)
{
if (item.Field != null)
continue;
if (item.State != ItemStates.Deleted)
continue;
// code
}
вместо того, где я обычно использовал бы:
foreach (var item in items.Where(i => i.Field != null && i.State != ItemStates.Deleted))
{
// code
}
Я даже видел комбинацию обоих. Мне очень нравится удобочитаемость с «продолжить», особенно в более сложных условиях. Есть ли разница в производительности? С запросом к базе данных я предполагаю, что будет. Как насчет обычных списков?
c#
readability
loops
filtering
Paprik
источник
источник
Ответы:
Я бы посчитал это подходящим местом для разделения команд и запросов . Например:
Это также позволяет вам дать хорошее самодокументируемое имя для результата запроса. Это также помогает вам увидеть возможности для рефакторинга, потому что намного проще реорганизовать код, который только запрашивает данные или только изменяет данные, чем смешанный код, который пытается сделать оба.
При отладке вы можете сломаться раньше
foreach
быстро проверить, соответствует ли содержимоеvalidItems
тому, что вы ожидаете. Вам не нужно входить в лямбду, если вам не нужно. Если вам нужно войти в лямбду, тогда я предлагаю выделить ее в отдельную функцию, а затем пройти через это.Есть ли разница в производительности? Если запрос поддерживается базой данных, то версия LINQ потенциально может выполняться быстрее, поскольку запрос SQL может быть более эффективным. Если это LINQ to Objects, то вы не увидите никакой реальной разницы в производительности. Как всегда, профилируйте свой код и исправьте узкие места, о которых действительно сообщается, вместо того, чтобы пытаться предсказать оптимизацию заранее.
источник
IEnumerable
Управляется толькоforeach
цикл.Where
лямбду и тело цикла (если лямбда возвращает true) один раз для каждого элемента.Конечно, есть разница в производительности, в
.Where()
результате чего для каждого отдельного элемента делается вызов делегата. Однако я не стал бы беспокоиться о производительности:Тактовые циклы, используемые при вызове делегата, ничтожны по сравнению с тактовыми циклами, используемыми в остальной части кода, который перебирает коллекцию и проверяет условия.
Потеря производительности при вызове делегата составляет порядка нескольких тактов, и, к счастью, мы давно прошли те дни, когда нам приходилось беспокоиться об отдельных тактах.
Если по какой-то причине производительность действительно важна для вас на уровне тактового цикла, используйте
List<Item>
вместоIList<Item>
, чтобы компилятор мог использовать прямые (и встроенные) вызовы вместо виртуальных вызовов, и чтобы итераторList<T>
, который на самом деле является аstruct
, не должен быть в штучной упаковке. Но это действительно мелочи.Запрос к базе данных - это другая ситуация, поскольку существует (по крайней мере, теоретически) возможность отправки фильтра в СУБД, что значительно повышает производительность: только совпадающие строки будут совершать путешествие из СУБД в вашу программу. Но для этого, я думаю, вам придется использовать linq, я не думаю, что это выражение может быть отправлено в СУБД как есть.
Вы действительно увидите преимущества того
if(x) continue;
момента, когда вам придется отлаживать этот код: пошаговое переключение междуif()
s иcontinue
s прекрасно работает; Единственный шаг в делегат фильтрации - это боль.источник
if(x) continue;
..Where
вызывается только один раз. То , что можно ссылаться на каждой итерации фильтра делегат (аMoveNext
иCurrent
на счетчику, когда они не получают оптимизированными).Where
вызывается только один раз. Починил это.