我正在编写101 Linq教程:
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
大多数例子都很简单,但是这个例子让我想到了一个循环:
[Category("Ordering Operators")]
[Description("The first query in this sample uses method syntax to call OrderBy and ThenBy with a custom comparer to " +
"sort first by word length and then by a case-insensitive sort of the words in an array. " +
"The second two queries show another way to perform the same task.")]
public void Linq36()
{
string[] words = { "aPPLE", "AbAcUs", "bRaNcH", "BlUeBeRrY", "ClOvEr", "cHeRry", "b1" };
var sortedWords =
words.OrderBy(a => a.Length)
.ThenBy(a => a, new CaseInsensitiveComparer());
// Another way. TODO is this use of ThenBy correct? It seems to work on this sample array.
var sortedWords2 =
from word in words
orderby word.Length
select word;
var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer());
无论我扔哪个单词组合,长度始终是第一个排序标准...即使我不知道第二个语句(没有orderby!)如何知道原始orderby子句是什么。< / p>
我疯了吗?任何人都可以解释Linq如何“记住”原始排序是什么?
答案 0 :(得分:4)
OrderBy
的返回类型不是IEnumerable<T>
。它是IOrderedEnumerable<T>
。这是一个“记住”所有顺序的对象,只要你不调用另一个将变量变回IEnumerable
的方法,它就会保留这些知识。
请参阅Jon Skeets精彩的博客系列Eduling,其中他重新实现了Linq-to-objects以获取更多信息。 OrderBy
/ ThenBy
上的关键条目为:
答案 1 :(得分:1)
这是因为LINQ是惰性的,第一个,即所有评估只在枚举序列时发生..已经构造的表达式树被执行。
答案 2 :(得分:1)
你的问题在表面上确实没有多大意义,因为你没有考虑延期执行的性质。在任何一种情况下,它都不会“记住”,它只是在真正需要之前才会被执行。如果你在调试器中运行你的例子,你会发现它们生成相同的(结构上无论如何)语句。考虑:
var sortedWords =
words.OrderBy(a => a.Length)
.ThenBy(a => a, new CaseInsensitiveComparer());
你明确告诉它OrderBy,ThenBy。每个语句都被堆叠起来,直到它们全部完成,并且finally查询被构造成看起来像(伪):
Select from sorted words, order by length, order by comparer
然后,一旦准备就绪,它就被执行并放入sortedWords
。现在考虑:
var sortedWords2 =
from word in words
orderby word.Length // You're telling it to sort here
select word;
// Now you're telling it to ThenBy here
var sortedWords3 = sortedWords2.ThenBy(a => a, new CaseInsensitiveComparer());
然后,一旦这些查询被叠加,它就会被执行。但是,直到你需要它才会被执行。 sortedWords3
在你采取行动之前不会有任何价值,因为延迟了它的需要。所以在这两种情况下,你基本上都是对编译器说:
注意:总而言之,LINQ不会“记住”,它只是在您完成指令执行之后才会执行。然后它将它们堆叠成一个查询,并在需要时立即运行它们。