我需要帮助理解LINQ。我的理解在哪里出错了?

时间:2016-03-26 14:17:44

标签: c# .net linq

我会尽最大努力去理解它,你让我知道我哪里出错了。

为简单起见,我们假设我们生活在一个只有

的单词中
  • 数字12345
  • 运营商%>及其通常的预防性

我想忽略当我做的事情

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
                            where i % 2 == 1
                            orderby i descending
                            select i; 
foreach ( var i in Filtererd ) 
{
   Console.WriteLine(i);
}

我首先理解的是查询本身不会创建Ienumerable<int>;它会创建与Expression Tree关联的查询。查询返回的元素在编译器创建的不可见函数中yield,如

public static IEnumerable<int> MyInvisibleFunction ( List<int> Source )
{
    foreach ( int i in Source.Reverse() )
    {
       if ( i % 2 == 1 ) 
       {
           yield return i;
       } 
    }
} 

(当然这是一个奇怪的例子,因为Source.Reverse()本身就是一个查询,但无论如何......)

现在我很困惑表达发辫在这里发挥作用。当我想到表达树时,我会想到像

这样的树
        (3 % 1 > 0)
          /      \ 
         /        \   
     (3 % 1)  >    0
      /   \ 
     3  %  1

在我创造的小世界里。但是,在我的LINQ查询中,这样的树会在哪里播放

from i in All
where i % 2 == 1
orderby i descending
select i

???这是我不明白的。我正在查看Expression class,我看到它如何创建我展示的示例树,但我不知道它会在我的查询中发挥作用。

2 个答案:

答案 0 :(得分:8)

  

我会尽力帮助你理解它,你让我知道我哪里出错了。

行。

  

我首先理解的是查询本身不会创建Ienumerable<int>;

这句话是完全错误的。

  

它创建与查询关联的表达式树。

这句话也完全错了。

  

查询返回的元素在编译器

创建的不可见函数中生成

这句话也完全错了。

  

这样的树在我的LINQ查询中进行播放

没有。您的查询不使用表达式树。

  

我正在查看Expression类,我看到它如何创建我展示的示例树,但我看不到它会发挥作用

没有。

  

想要掩饰我做的事情

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
                        where i % 2 == 1
                        orderby i descending
                        select i; 
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

让我们分解吧。首先,编译器将其转换为

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = All.Where(i => i % 2 == 1).OrderBy(i => i);                          
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

接下来编译器执行重载解析并评估扩展方法

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = 
  Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, i => i % 2 == 1)), 
    i => i));                           
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

接下来的羔羊被玷污了:

static bool A1(int i) { return i % 2 == 1; )
static int A2(int i) { return i }
...
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = 
  Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, new Func<int, bool>(A1))), 
    new Func<int, int>(A2)));                           
foreach (var i in Filtererd ) 
  Console.WriteLine(i);

实际上,这并不是羔羊如何完全被贬低;它们也被缓存,但让我们忽略这个细节。

我认为你不希望foreach脱毒。有关详细信息,请参阅C#规范。

如果您想知道Where和OrderBy的作用,请阅读源代码。

答案 1 :(得分:1)

  

表达式树不会在您的查询中发挥作用,因为您的源是常规的内存列表。 - Theodoros Chatzigiannakis

这是真的。

没有生成不可见的迭代器函数。您的查询转换为:

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered =
 All
 .Where(i => i % 2 == 0)
 .OrderByDescending(i => i);

不需要自定义迭代器。该语言只调用现有的库函数。

IQueryable的情况相同,只是lambda参数不作为委托传递,而是作为表达式树传递。

您可以通过AsQueryable()来电here中的评论来查看此操作。