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

时间:2019-06-12 19:40:02

标签: c# linq difference

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

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

    return oldestPerson;
}

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;
}

2 个答案:

答案 0 :(得分:6)

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

如果我们假设这是内存中数据(LINQ对象),则类似IEnumerable<Person>List<Person>Person[]

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

Person oldestPerson = people.MaxBy(x => x.Age);

再一次,而不是相当,其效率要比循环好,但的效率要比OrderByDescending + FirstOrDefault ...要注意对于空输入,它的行为是(可能会抛出而不是返回null。)


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

SELECT TOP 1 *
FROM People
ORDER BY Age DESC

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

SELECT *
FROM People

然后在我们进行本地迭代以查看哪个最旧时通过网络获取了一切

答案 1 :(得分:-2)

关于LINQ查询的一件事并不是立即显而易见的,它们往往会“快速失败”。也就是说,它们会在满足指定条件后立即退出循环,而不是遍历整个序列。

例如,FirstOrDefault()从序列中获取第一个项目,如果序列中有任何项目,则立即退出。如果没有,则立即返回null。它不会遍历整个序列。

但是,您的for循环遍历序列中的每个元素。如果序列非常大,则可能很耗时。此外,如果退出条件错误或完全丢失,则可能返回错误的元素(尽管在LINQ表达式中也可能发生)。

LINQ表达式非常高效,它仅以最快的速度检索满足请求所需的数据。您不太可能编写效率更高的for循环(尽管并非不可能)。