C# LINQ对象是否在内部进行任何调优?

C# LINQ对象是否在内部进行任何调优?,c#,linq-to-objects,C#,Linq To Objects,我想知道LINQtoObjects如何确定集合中查询的最佳方式 我的意思是,以下LINQ查询之间是否存在任何差异(在LINQ内部的工作方式上): var lst1 = ListOfComplexClass.Where(p => p.StrValue == "Whatever") .Select(p => p.StrValue); 及 例如,第一个函数是否会过滤ListOfComplexClass的集合,然后获取StrValu

我想知道LINQtoObjects如何确定集合中查询的最佳方式

我的意思是,以下LINQ查询之间是否存在任何差异(在LINQ内部的工作方式上):

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

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

在这种特殊情况下,这并不重要。您直接投影一个字符串,因此不会创建新对象,并且仍然只有一个比较。另一方面,在某些情况下(投射到另一种类型中),这可能很重要。我不相信LINQ会试图优化这些预测,因为它们可能包含副作用

我想知道LINQtoObject是否在集合中寻找查询的最佳方式

不,不可能。这里没有“引擎”。这些调用在一个直接链中对彼此的输出起作用。如果第二个比这更快,则必须进行优化


也许LINQtoSQL或LINQtoEntities(IQueryable)可以优化某些东西,但不能优化LINQtoObject

Linq to对象不使用像Linq to sql这样的表达式,因此没有这样的优化空间-每个Linq命令都返回另一个可枚举或值。使用中的
时可能会有一些优化。。在里面哪里选择..
syntaxebycompiler,但我也不希望出现任何复杂的情况。在您的示例中,首先使用
where
应该稍微快一点(至少在理论上),因为
where
select
之间的转换已经被过滤,但我认为我们甚至无法测量这种差异,因为它实际上只是在调用方和被调用方之间传递值。然而,若您要以某种方式转换所选择的值,那个么差异将是明显的,因为您将在已经过滤的集合上创建新对象

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

(我假设您在第一个选项的
中选择
,是指
p=>p.StrValue
。)

事实上,这比那更微妙

假设你在第一个上使用了一个枚举器

var lst1 = ListOfComplexClass.Where(p => p.StrValue == "Whatever")
                             .Select(p => p.StrValue);
var e = lst1.GetEnumerator();
当您调用
e.MoveNext()
时,将发生的情况是
Select
将在
ListOfComplexClass的迭代器上调用
MoveNext()
,其中(p=>p.StrValue==“Whatever”)
将调用
MoveNext()
ListOfComplexClass的迭代器,直到它找到一个元素
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
将在
ListOfComplexClass的迭代器上调用
MoveNext()
。选择(p=>p.StrValue)
,直到它找到一个元素
p
,其中
p==“which”
。当然,在
ListOfComplexClass.Select(p=>p.StrValue)
的迭代器上调用
MoveNext()
将在
ListOfComplexClass
的迭代器上调用
MoveNext()
,并返回该迭代器当前的投影

乔恩·斯基特有一个很好的类比,我在这里将其引用。想象一副随机排列的牌。想象一下这些疑问

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

现在想象一下使用第一个查询的结果。事情是这样的

选择
询问
卡的位置

其中
询问
卡片组

*
其中
检查卡套

如果卡片的套装是钻石或心脏,它会将卡片返回到
Select
,然后
Select
将卡片投影到其套装并返回

如果这张牌的花色不是钻石或心形,
Where
要求从牌组中取出另一张牌并循环回*

第二个查询是这样的

其中
询问
选择
一套西装

选择
询问
卡片组

deck
返回要选择的卡

选择
将卡投影到适合的位置

*
其中
选择
检查西装

如果西装是钻石或心脏,
其中
返回西装


如果西装不是钻石或心脏,
其中
要求
选择
另一件西装,并循环回*

,如果您呈现的没有区别

但如果你把收费表放在那里的某个地方,它可能会有所不同

LINQtoObject,就像LINQtoSQL一样,仍然使用延迟执行,即使它只是处理内存中的对象

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


通常,如果您链接IEnumerable扩展,那么这不会有什么区别。但是,如果您需要中途更改类型,或者调用类似于ToList的命令,那么这将改变执行顺序。

谢谢,当我使用循环收集或将其作为列表返回时,我当然在讨论调优。
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);