这个LINQ示例的复杂性是什么?

时间:2010-10-24 14:33:32

标签: c# .net linq performance

我想知道LINQ的一般性能。我承认,它很方便,但LINQ的表现如何?我知道这是一个广泛的问题。所以我想问一个特定的例子:

我有一个匿名类型:

var users = reader.Select(user => new MembershipUser(reader.Name, reader Age));

现在,我想将其转换为MembershipUserCollection

所以我这样做:

MembershipUserCollection membershipUsers = new MembershipUserCollection();
users.ToList().ForEach(membershipUsers.Add); //what is the complexity of this line?

最后一行的复杂性是多少?是n ^ 2吗?

ToList()方法是否为用户的每个元素进行迭代并将其添加到列表中? 或者ToList()的工作方式不同?因为如果不是,我发现使用代码的最后一行而不是简单的原因很难判断:

foreach (var user in users)
{
    membershipUsers.Add(user);
}

3 个答案:

答案 0 :(得分:2)

您的示例对您的问题并不是特别有用,因为ToList()实际上与支持LINQ的其他扩展方法不在同一类扩展方法中。 ToList()扩展方法是转换操作,而不是查询操作。 LINQ中的实际值是通过组合多个LINQ查询操作和提高的可读性而构建的复合查询的延迟执行。在LINQ2SQL中,您还可以构建任意查询,然后将其推送到数据库服务器以进行实际执行,利用数据库可能具有的优化来提高性能。

总的来说,我认为性能问题很大程度上取决于您构建实际查询的程度,并且与程序员了解工具和数据的程度有关,而不是工具的实现程度。在您的情况下,构建临时列表是没有意义的,只是为了能够调用方便ForEach方法,如果您关心的只是性能。你最好只是迭代你已经拥有的枚举(正如你所怀疑的那样)。 LINQ不会阻止程序员编写错误的代码,尽管它可能会为不了解LINQ如何工作的人掩盖不良代码。

对于任何使用LINQ的程序,您都可以构建一个不使用LINQ的等效程序。可能实际上你可以提高性能。不过,我会提出,LINQ使编写可读代码比使用非LINQ解决方案更容易。通过这个,我的意思是更紧凑和可理解。它还使编写可组合代码变得更容易,当以延迟方式执行时,其执行性能优于非LINQ组合。通过将代码分解为可组合部分,可以简化代码并提高可理解性。

我认为这里的诀窍是真正了解LINQ在哪里有意义,而不是把它当作一个闪亮的新工具,你现在需要用它来处理你遇到的每一个问题。不过,这个闪亮的新工具的好处在于它在很多情况下确实派上用场。

答案 1 :(得分:1)

它是 O(n) - 因为.ToList()通过枚举迭代一次并将元素复制到生成的List<T>中(其插入是 O(1))。因此复杂性很好。

您可能会看到的实际问题是,您创建了一个全新的临时 List<T>,只是将其内容复制到另一个列表中(之后将其丢弃) )。

我怀疑这只是因为在.ForEach()上使用List<T>方法的便利性。尽管如此,我们仍然可以编写IEnumerable<T> s的直接实现代码,这样可以节省这个多余的复制 - 或者只是编写

foreach (var user in users) membershipUsers.Add(user)

基本上是你想要表达的东西; - )

答案 2 :(得分:0)

转换为列表将具有与遍历序列相同的复杂性,这可能实际上取决于序列的生成方式。内存列表中的正常选择是O(n)。

在List和foreach循环上使用ForEach的性能归结为调用委托的开销和创建和使用枚举器的开销,我不能说哪一个更快,但如果两者都用于-memory list,复杂性是一样的。