LINQ To Object是否在内部进行任何调整?

时间:2011-02-14 22:28:31

标签: c# linq-to-objects

我想知道LINQ to Objects如何确定在集合中查询的最佳方式?

我的意思是,以下LINQ查询之间是否有任何区别(LINQ如何在内部工作):

var lst1 = ListOfComplexClass.Where(p => p.StrValue == "Whatever")
                             .Select(p => p.StrValue);

var lst2 = ListOfComplexClass.Select(p => p.StrValue)
                             .Where(p => p == "Whatever");

例如,第一个会过滤ListOfComplexClass的集合,然后获取StrValue属性吗? 或者它会进行一些调整并首先执行Select,然后过滤返回的集合?

5 个答案:

答案 0 :(得分:2)

  

我想知道LINQ to Object是否寻找在集合中查询的最佳方式?

不,它不能。这里没有'引擎'。这些呼叫正在以直接链的方式处理每个其他输出。如果第二个比这更快,那么你将不得不进行优化。

也许Linq-to-SQL或Linq-to-Entities(IQueryable)可以优化某些东西,但不能优化Linq-to-Objects。

答案 1 :(得分:2)

  

例如..第一个会过滤ListOfComplexClass的集合,然后获取StrValue属性吗?或者它会让一些人调整并执行Select然后过滤返回的集合?

(我假设您在第一个p => p.StrValue中表示Select。)

实际上,它比那更微妙。

让我们假设您在第一个上采用了一个调查员。

var lst1 = ListOfComplexClass.Where(p => p.StrValue == "Whatever")
                             .Select(p => p.StrValue);
var e = lst1.GetEnumerator();

当您致电e.MoveNext()时,Select会在MoveNext()的迭代器上调用ListOfComplexClass.Where(p => p.StrValue == "Whatever"),这将调用MoveNext() ListOfComplexClass的迭代器{1}}直到找到带p的元素p.StrValue == "Whatever"。然后,此p的预计结果将返回为e.Current

现在让我们考虑第二个问题。让我们说你带一个调查员。

var lst2 = ListOfComplexClass.Select(p => p.StrValue)
                             .Where(p => p == "Whatever");
var e = lst2.GetEnumerator();

当您致电e.MoveNext()时,Where会在MoveNext()的迭代器上调用ListOfComplexClass.Select(p => p.StrValue),直到找到p元素p == "Whatever"为止。当然,在MoveNext()的迭代器上调用ListOfComplexClass.Select(p => p.StrValue)将在MoveNext()的迭代器上调用ListOfComplexClass并返回该迭代器的Current投影。

Jon Skeet有一个很好的比喻,我会在这里偷。想象一下随机顺序的一副牌。想象一下查询

var suits = deck.Where(c => c.Suit == Suit.Diamond || c.Suit == Suit.Heart)
                .Select(c => c.Suit)

var suits = deck.Select(c => c.Suit)
                .Where(c => c == Suit.Diamond || c == Suit.Heart);

现在想象一下消耗第一个查询的结果。它是这样的。

Select要求Where提供一张卡片。

Where要求deck提供一张卡片。

* Where检查卡片的套装。

如果卡片的套装是钻石或心形,则会将卡片退回SelectSelect将卡片投放到套装中并将其退回。

如果卡片的套装不是钻石或心脏,Where会从卡片中请求另一张卡片并循环回*。

第二个查询是这样的。

Where要求Select提起诉讼。

Select要求deck提供一张卡片。

deck会将卡片退回到选择中。

Select将卡片投入其中。

* Where检查来自Select的诉讼。

如果西装是钻石或心形,Where会退回诉讼。

如果套装不是钻石或心形,Where会要求Select寻找其他套装并循环回*。

答案 2 :(得分:0)

在这种特殊情况下无所谓。您正在直接投影字符串,因此没有创建新对象,您仍然只有一个比较。另一方面,可能存在可能重要的情况(投射到另一种类型)。我不相信LINQ会尝试优化投影,因为它们可能包含副作用。

答案 3 :(得分:0)

Linq to objects不使用像linq这样的表达式,因此没有像这样的优化位置 - 每个linq命令返回另一个可枚举或值。在编译器中使用from .. in .. where .. select ..语法时可能会有一些优化,但我也不希望有任何复杂的问题。在使用where的示例中,首先应该稍微更快(理论上至少),因为whereselect之间的转换已经过滤,但我我认为我们甚至无法衡量这种差异,因为它实际上只是在调用者和被调用者之间传递值。但是,如果你要以某种方式改变你正在选择的价值,那么差异将是显而易见的,因为你将在已经过滤的集合上创建新对象。

答案 4 :(得分:0)

如果您出席的情况没有区别。

但是如果你把ToList放到ToArray那里,它可能会有所作为。

LINQ to Objects,作为LINQ to SQL,仍然使用延迟执行,即使它只是在内存对象中工作。

这是因为IEnumerable上的LINQ扩展使用表达式树。这意味着只有在需要时才执行LINQ表达式。

通常如果你链接IEnumerable扩展,那么它将没有什么区别。但是如果你需要在一半时间改变类型,或者调用类似ToList的东西,那么这将改变执行的顺序。