linq:单独的orderby和thenby语句

时间:2012-12-27 19:50:46

标签: c# linq

我正在编写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如何“记住”原始排序是什么?

3 个答案:

答案 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在你采取行动之前不会有任何价值,因为延迟了它的需要。所以在这两种情况下,你基本上都是对编译器说:

  1. 等到我完成了我的查询
  2. 从源中选择
  3. 按长度排序
  4. 然后通过比较器
  5. 好的,你的东西。
  6. 注意:总而言之,LINQ不会“记住”,它只是在您完成指令执行之后才会执行。然后它将它们堆叠成一个查询,并在需要时立即运行它们。