LINQ: различия между синглом Где с несколькими условиями и последовательными Wheres с одним условием
Есть ли недостаток в объединении нескольких Where
в LINQ вместо использования одного Where
с несколькими условиями?
Я спрашиваю, потому что использование нескольких Where
может помочь значительно снизить сложность и улучшить ремонтопригодность моего кода.
Рассмотрим следующий код, chargeList
- это List<Charge>
, который является источником BindingSource
:
IEnumerable<Charge> matchingCharges = chargeList;
if(!string.IsNullOrWhiteSpace(channelAbbr))
matchingCharges = matchingCharges
.Where(c => c.ChannelAbbreviation == channelAbbr);
if(deliveryNoteDate.HasValue)
matchingCharges = matchingCharges
.Where(c => c.ArrivalAt == deliveryNoteDate.Value);
if(chargeID.HasValue)
matchingCharges = matchingCharges
.Where(c => c.ChargeID == chargeID.Value);
Этот сжатый код будет обрабатывать все комбинации фильтров, ни одного, ни одного, ни одного.
В противном случае мне пришлось бы использовать if-else
и несколько условий в одном Where
.
Это лучшее, что приходит мне на ум:
// important to keep code readable:
bool filterChannel = !string.IsNullOrWhiteSpace(channelAbbr);
bool filterDate = deliveryNoteDate.HasValue;
bool filterID = chargeID.HasValue;
if(!filterChannel && !filterDate && !filterID)
{
// take all
matchingCharges = chargeList;
}
else
{
matchingCharges = chargeList
.Where(c =>
filterChannel ? c.ChannelAbbreviation == channelAbbr : true
&& filterDate ? c.ArrivalAt == deliveryNoteDate.Value : true
&& filterID ? c.ChargeID == chargeID.Value : true);
}
Итак, каковы различия между ними, являются ли они незначительными? Имеет ли поставщик LINQ?
Ответы
Ответ 1
Семантически, нет разницы в случае Where
(контраст OrderBy
, который требует большей осторожности). На уровне реализации это просто несколько предикатов с простыми деревьями выражений вместо одного предиката со сложным деревом выражений; но большинство двигателей тоже справятся с этим.
Для того, что вы делаете, несколько Where
идеальны.
Ответ 2
Мне было интересно то же самое. Вот почему я попробовал это в своем собственном приложении.
У меня есть список с большим количеством записей, и это то, что я пробовал:
//TEST 1
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var hoursLinq = _hourDataSource.Hours
.Where(hour => hour.Id == profile.Id)
.Where(hour => hour.DayName.Equals("Maandag"))
.Where(hour => hour.Day == 1)
.Select(hour => hour);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts1 = stopWatch.Elapsed;
//TEST 2
stopWatch = new Stopwatch();
stopWatch.Start();
var hoursLinq2 = _hourDataSource.Hours
.Where(hour => hour.Id == profile.Id)
.Select(hour => hour);
if (hoursLinq2.Count() != 0)
{
var hoursLinq3 = _hourDataSource.Hours
.Where(hour => hour.DayName.Equals("Maandag"))
.Select(hour => hour);
if (hoursLinq3.Count() != 0)
{
var hoursLinq4 = _hourDataSource.Hours
.Where(hour => hour.Day == 1)
.Select(hour => hour);
}
}
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts2 = stopWatch.Elapsed;
//TEST 3
stopWatch = new Stopwatch();
stopWatch.Start();
var hoursLinq5 = _hourDataSource.Hours
.Where(hour => hour.Id == profile.Id &&
hour.DayName.Equals("Maandag") &&
hour.Day == 1)
.Select(hour => hour);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts3 = stopWatch.Elapsed;
Каждый раз (ts1, ts2, ts3) имел такое маленькое различие в прошедшее время, что я уверен, что вы можете его игнорировать.
Я предполагаю, что это личное предпочтение, мне нравится множество, из-за которого читаемость