使用foreach循环和LINQ进行操作之间有什么区别?

Val*_*eri 0 c# linq difference

我正在解决一个问题,并且我知道这些代码以不同的方式工作,但是我不明白为什么第二个代码不正确以及有什么区别。

public Person GetOldestMember()
{
    Person oldestPerson = people.OrderByDescending(x => x.Age).FirstOrDefault();

    return oldestPerson;
}
Run Code Online (Sandbox Code Playgroud)

public Person GetOldestMember()
{
    Person oldestPerson = new Person(-1); //this is a constructor with parameter age

    foreach (Person person in people)
    {
        if (person.Age > oldestPerson.Age)
        {
            oldestPerson = person;
        }
    }

    return oldestPerson;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 6

  • LINQ已针对可读性进行了优化;易于编写,阅读和理解
  • 但是它并不总是那么高效。它不能利用自定义迭代器之类的东西,并且可能涉及更多对象
  • 简单的操作(OrderBy例如)可能非常昂贵
  • 但是然后...在大多数情况下,这并不重要,可读性是赢家
  • 但是然后...在某些情况下,这很重要 :)

如果我们假设这是内存中的数据(LINQ对象) -有点像IEnumerable<Person>List<Person>Person[],等:

请注意,排序是一项相对昂贵的操作,使用LINQ时通常也意味着创建数据副本(以免更改源)。有一些外部扩展方法可以在LINQ概念内更有效地执行此操作,即

Person oldestPerson = people.MaxBy(x => x.Age);
Run Code Online (Sandbox Code Playgroud)

同样,不是高效的循环,但效率比OrderByDescending+ FirstOrDefault...只是注意如何的行为空输入(它可能抛出而不是返回null)。


但是,正如Dzyann在评论中观察到的:people这可能是一个IQueryable<Person>-类似于DbSet<Person>EF或LINQ-to-SQL(等等)中的a,在这种情况下,一切都会改变:现在,我们谈论的是将查询下推到外部资源的查询,在这种情况下,OrderByDescending+ FirstOrDefault可能会变成SQL,例如:

SELECT TOP 1 *
FROM People
ORDER BY Age DESC
Run Code Online (Sandbox Code Playgroud)

而且我们已经成为英雄。如果我们通过进行foreach了此操作IQueryable<Person>,我们将发出:

SELECT *
FROM People
Run Code Online (Sandbox Code Playgroud)

然后在我们进行本地迭代以查看最旧的网络时通过网络获取所有内容

  • 我想指出的是,根据底层集合的实际情况,排序的顺序可能会更快。如果必须将所有人员从一台较远的服务器存储到内存中,然后遍历它们来确定哪一个年龄较大(与SQL Server Sort / Top比较),然后仅检索1 Person。有趣的是,OP表示第二种方法(似乎更快)是错误的方法。也许他的同事正在考虑与ORM相关的问题。 (2认同)