【问题标题】:LINQ: differences between single Where with multiple conditions and consecutive Wheres with single condition [duplicate]LINQ:具有多个条件的单个Where与具有单个条件的连续Where之间的差异[重复]
【发布时间】:2014-05-15 09:50:43
【问题描述】:

在 LINQ 中连接多个 Where 而不是在多个条件下使用单个 Where 有什么缺点吗?

我之所以这么问,是因为使用多个 Where 可以帮助大大降低代码的复杂性并提高代码的可维护性。

考虑以下代码,chargeListList<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);

这个简洁的代码将处理过滤器的所有组合,无,一,二,全部。

否则我必须在单个Where 中使用if-else 和多个条件。

这是我想到的最好的:

// 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 提供程序重要吗?

【问题讨论】:

标签: c# linq


【解决方案1】:

语义上,Where 的情况没有区别(对比OrderBy,需要多加注意)。在实现层面,它只是简单的表达式树的多个谓词,而不是复杂表达式树的单个谓词;但大多数引擎都可以应付得很好。

对于你正在做的事情,多个Where 是理想的。

【讨论】:

  • 而不是单个谓词和复杂的表达式树请注意,如果您使用 LINQ to Objects,多个 Where 语句的谓词将组合成一个谓词,并且只会调用一个 foreach 循环,而不管链接在一起的 Where 子句的数量。
  • @sloth 好吧,那是 bit 取决于其他情况;但是是的,在许多(绝不是所有)情况下,Iterator&lt;T&gt;.Where(...) 方法将用于组合它们,从而减少循环。
  • @sloth 你能提供一个合并谓词部分的来源吗?
  • @sgarg 当然,看看here。在WhereEnumerableIterator 上调用Where(例如,通过组合Where 调用)将导致使用单个Iterator,并且所有谓词都简单地与&amp;&amp;“组合”
【解决方案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) 在经过的时间上都有如此小的差异,我很确定你可以忽略它。

我猜这是个人喜好,我喜欢多个 where's 因为它的可读性

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多