我应该使用两个“where”条款还是“&&”在我的LINQ查询?

时间:2009-03-20 01:27:57

标签: c# .net linq

在编写具有多个“和”条件的LINQ查询时,我应该编写一个包含where或多个&&子句的where子句,每个条件一个吗?

static void Main(string[] args)
{
    var ints = new List<int>(Enumerable.Range(-10, 20));

    var positiveEvensA = from i in ints
                         where (i > 0) && ((i % 2) == 0)
                         select i;

    var positiveEvensB = from i in ints
                         where i > 0
                         where (i % 2) == 0
                         select i;

    System.Diagnostics.Debug.Assert(positiveEvensA.Count() == 
                                         positiveEvensB.Count());
}

positiveEvensA positiveEvensB 之间是否存在个人偏好或编码风格(长线,可读性等)之外的差异?

我想到的一个可能的区别是,不同的LINQ提供程序可能能够更好地处理多个where而不是更复杂的表达;这是真的吗?

5 个答案:

答案 0 :(得分:46)

我个人总是会选择&amp;&amp;只要不使声明无法理解,就可以使用两个条款。

在你的情况下,它可能根本不会引起注意,但如果你有一个大型集合,并且你使用了这个查询的所有结果,那么有2个where子句肯定会对性能产生影响。例如,如果在结果上调用.Count(),或者遍历整个列表,则会运行第一个where子句,创建一个将再次完全枚举的新IEnumerable,并使用第二个委托。

将2个子句链接在一起会导致查询形成一个在枚举集合时运行的委托。这导致一次枚举通过集合,每次返回结果时调用一次委托。

如果你拆分它们,情况会发生变化。当你的第一个where子句枚举原始集合时,第二个where子句枚举它的结果。这可能(最坏的情况)导致通过集合的2个完整枚举和每个成员调用的2个委托,这可能意味着这个声明(理论上)可能需要2倍的运行时速度。

如果您决定使用2 where子句,那么首先放置更具限制性的子句将有很大帮助,因为第二个where子句仅在传递第一个子句的元素上运行。

现在,在你的情况下,这无关紧要。在大型系列上,它可以。作为一般经验法则,我选择:

1)可读性和可维护性

2)表现

在这种情况下,我认为这两个选项都是同样可维护的,所以我会选择性能更高的选项。

答案 1 :(得分:20)

这主要是个人风格问题。就个人而言,只要where子句适合一行,我就对这些子句进行分组。

使用多个where s往往性能较差,因为它需要对每个元素进行额外的委托调用。然而,它可能是一个微不足道的问题,只有在剖析器显示它是一个问题时才应该考虑。

答案 2 :(得分:4)

性能问题仅适用于基于内存的集合... Linq to SQL生成延迟执行的表达式树。更多详情:

Multiple WHERE Clauses with LINQ extension methods

答案 3 :(得分:1)

与其他人一样,这更像是个人偏好。我喜欢使用&amp;&amp;因为它更具可读性并且模仿其他主流语言的语法。

答案 4 :(得分:0)

正如 Jared Par 已经说过的:这取决于您的个人喜好、可读性和用例。例如,如果您的方法有一些可选参数,并且您想过滤给定的集合,那么 Where 是完美的:

IEnumerable<SomeClass> matchingItems = allItems;
if(!string.IsNullOrWhiteSpace(name))
    matchingItems = matchingItems
       .Where(c => c.Name == name);
if(date.HasValue)
    matchingItems = matchingItems
       .Where(c => c.Date == date.Value);
if(typeId.HasValue)
    matchingItems = matchingItems
       .Where(c => c.TypeId == typeId.Value);
return matchingItems;

如果你想用 && 做到这一点,玩得开心;)

我不同意 JaredReed 的地方是多个 Where 应该具有的性能问题。实际上,Where 的优化方式是将多个谓词组合为一个,如您所见 here

但我想知道如果集合很大并且有多个 Where 都必须评估,它是否真的没有太大影响。我很惊讶以下 benchmark 显示即使是多 Where 方法也稍微更有效。总结:

<头>
方法 平均 错误 StdDev
MultipleWhere 1.555 秒 0.0310 秒 0.0392 s
MultipleAnd 1.571 秒 0.0308 s 0.0649 s

这是基准代码,我认为它足以进行此测试:

#LINQPad optimize+

void Main()
{
    var summary = BenchmarkRunner.Run<WhereBenchmark>();
}


public class WhereBenchmark
{
    string[] fruits = new string[] { "apple", "mango", "papaya", "banana", "guava", "pineapple" };
    private IList<string> longFruitList;
    
    [GlobalSetup]
    public void Setup()
    {
        Random rnd = new Random();
        int size = 1_000_000;
        longFruitList = new List<string>(size);
        for (int i = 1; i < size; i++)
            longFruitList.Add(GetRandomFruit());

        string GetRandomFruit()
        {
            return fruits[rnd.Next(0, fruits.Length)];
        }
    }


    [Benchmark]
    public void MultipleWhere()
    {
        int count = longFruitList
            .Where(f => f.EndsWith("le"))
            .Where(f => f.Contains("app"))
            .Where(f => f.StartsWith("pine"))
            .Count(); // counting pineapples
    }
    
    [Benchmark]
    public void MultipleAnd()
    {
        int count = longFruitList
            .Where(f => f.EndsWith("le") && f.Contains("app") && f.StartsWith("pine"))
            .Count(); // counting pineapples
    }
}