我想知道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
,然后过滤返回的集合?
答案 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
投影。
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
检查卡片的套装。
如果卡片的套装是钻石或心形,则会将卡片退回Select
并Select
将卡片投放到套装中并将其退回。
如果卡片的套装不是钻石或心脏,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
的示例中,首先应该稍微更快(理论上至少),因为where
和select
之间的转换已经过滤,但我我认为我们甚至无法衡量这种差异,因为它实际上只是在调用者和被调用者之间传递值。但是,如果你要以某种方式改变你正在选择的价值,那么差异将是显而易见的,因为你将在已经过滤的集合上创建新对象。
答案 4 :(得分:0)
如果您出席的情况没有区别。
但是如果你把ToList放到ToArray那里,它可能会有所作为。
LINQ to Objects,作为LINQ to SQL,仍然使用延迟执行,即使它只是在内存对象中工作。
这是因为IEnumerable上的LINQ扩展使用表达式树。这意味着只有在需要时才执行LINQ表达式。
通常如果你链接IEnumerable扩展,那么它将没有什么区别。但是如果你需要在一半时间改变类型,或者调用类似ToList的东西,那么这将改变执行的顺序。