什么是LINQ其实编译? [英] What is LINQ Actually Compiled To?

查看:183
本文介绍了什么是LINQ其实编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

这样做的背景是,我与有关LINQ如何编译另一个明确知识的用户评论了最近的谈话。我第一次总结,并表示LINQ被编译成一个for循环。虽然这是不正确的,其他栈,如这个是LINQ查询编译为一个lambda与它里面的循环。当该变量被列举为在第一时间(结果被存储之后),这是再调用。另一个用户说,LINQ需要额外的优化,例如哈希算法。我找不到任何证明文件或反对这一点。

The background for this is that I had a recent conversation in the comments with another clearly knowledgeable user about how LINQ is compiled. I first "summarized" and said LINQ was compiled to a for loop. While this isn't correct, my understanding from other stacks such as this one is that the LINQ query is compiled to a lambda with a loop inside of it. This is then called when the variable is enumerated for the first time (after which the results are stored). The other user said that LINQ takes additional optimizations such as hashing. I couldn't find any supporting documentation either for or against this.

我知道这看起来像一个非常不起眼的点,但我一直觉得,如果我不明白事情是如何工作的彻底,它的将是很难理解为什么我不能正确地使用它。

I know this seems like a really obscure point but I have always felt that if I don't understand how something works completely, its going to be difficult to understand why I'm not using it correctly.

问题

所以,让我们下面很简单的例子:

So, lets take the following very simple example:

var productNames = 
    from p in products 
    where p.Id > 100 and p.Id < 5000
    select p.ProductName;



这是什么说法的真正的编译在CLR?不LINQ采取哪些优化过我只是写一个手动解析结果的功能?这只是语义还是有更给它比?

What is this statement actually compiled to in CLR? What optimizations does LINQ take over me just writing a function that manually parses the results? Is this just semantics or is there more to it than that?

澄清

显然,我问这个问题,因为我不明白什么是LINQ黑盒子里面的样子。虽然我明白,LINQ是复杂的(和强大的),我主要找无论是CLR或功能相当于一个LINQ声明的一个基本的了解。有伟大的网站在那里帮助了解如何创建一个LINQ语句,但很少有这些似乎就如何这些实际编译或运行任何指导。

Clearly I'm asking this question because I don't understand what the inside of the LINQ "black box" looks like. Even though I understand that LINQ is complicated (and powerful), I'm mostly looking for a basic understanding of either the CLR or a functional equivalent to a LINQ statement. There are great sites out there for helping understand how to create a LINQ statement but very few of these seem to give any guidance on how those are actually compiled or run.

旁注的 - 我绝对会通过LINQ约翰飞碟双向系列对象读

Side Note - I will absolutely read through the John Skeet series on linq to objects.

边注2 的 - 我不应该标记这个作为的LINQ to SQL。我理解微ORM的ORM怎样的工作。这真的是除了问题的要点。

Side Note 2 - I shouldn't have tagged this as LINQ to SQL. I understand how ORM's and micro-ORM's work. That is really besides the point of the question.

推荐答案

有关LINQ到对象,这个被编译成一组静态方法调用:

For LINQ to Objects, this is compiled into a set of static method calls:

var productNames = 
    from p in products 
    where p.Id > 100 and p.Id < 5000
    select p.ProductName;



变成了:

Becomes:

IEnumerable<string> productNames = products
                                       .Where(p => p.Id > 100 and p.Id < 5000)
                                       .Select(p => p.ProductName);

这使用了的 可枚举 类型,所以实际上编译:

This uses extension methods defined in the Enumerable type, so is actually compiled to:

IEnumerable<string> productNames = 
     Enumerable.Select(
        Enumerable.Where(products, p => p.Id > 100 and p.Id < 5000),
        p => p.ProductName
     );

的lambda表达式来处理这都变成了编译器的方法。在那里的拉姆达变成可设置为 Func键℃的方法,产品,布尔> ,并选择到 Func键<产品,字符串方式>

The lambda expressions to handle this are turned into methods by the compiler. The lambda in the where is turned into a method which can be set to a Func<Product, Boolean>, and the select into a Func<Product, String>.

有关透彻的解释,看到的Jon飞碟双向的博客系列:重新实现LINQ到对象。他走过的是如何工作的,包括编译器转换(从查询语法方法调用),该方法是如何实现的,等整个过程。

For a thorough explanation, see Jon Skeet's blog series: Reimplementing LINQ to Objects. He walks through the entire process of how this works, including the compiler transformations (from query syntax to method calls), how the methods are implemented, etc.

请注意,LINQ to SQL和的IQueryable< T> 的实现是不同的。在表达式来; T> 由拉姆达产生被传递到查询提供商,进而以某种方式摇身一变(它是由供应商怎么办。这一点)到呼叫,典型地在一个ORM的情况下在服务器上运行

Note that LINQ to Sql and IQueryable<T> implementations are different. The Expression<T> that is generated by the lambda is passed into the query provider, which in turn is "transformed" in some manner (it's up to the provider how to do this) into calls, typically run on the server in the case of an ORM.

有关该方法,例如:

    private static IEnumerable<string> ProductNames(IEnumerable<Product> products)
    {
        var productNames =
            from p in products
            where p.Id > 100 && p.Id < 5000
            select p.ProductName;
        return productNames;
    }



被编译到以下IL:

Gets compiled to the following IL:

  .method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<string> ProductNames(class [mscorlib]System.Collections.Generic.IEnumerable`1<class ConsoleApplication3.Product> products) cil managed
{
    .maxstack 3
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable,
        [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<string> enumerable2)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate3
    L_0007: dup 
    L_0008: brtrue.s L_001d
    L_000a: pop 
    L_000b: ldnull 
    L_000c: ldftn bool ConsoleApplication3.Program::<ProductNames>b__2(class ConsoleApplication3.Product)
    L_0012: newobj instance void [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool>::.ctor(object, native int)
    L_0017: dup 
    L_0018: stsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, bool> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate3
    L_001d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<class ConsoleApplication3.Product>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
    L_0022: ldsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, string> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate5
    L_0027: dup 
    L_0028: brtrue.s L_003d
    L_002a: pop 
    L_002b: ldnull 
    L_002c: ldftn string ConsoleApplication3.Program::<ProductNames>b__4(class ConsoleApplication3.Product)
    L_0032: newobj instance void [mscorlib]System.Func`2<class ConsoleApplication3.Product, string>::.ctor(object, native int)
    L_0037: dup 
    L_0038: stsfld class [mscorlib]System.Func`2<class ConsoleApplication3.Product, string> ConsoleApplication3.Program::CS$<>9__CachedAnonymousMethodDelegate5
    L_003d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<class ConsoleApplication3.Product, string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>)
    L_0042: stloc.0 
    L_0043: ldloc.0 
    L_0044: stloc.1 
    L_0045: br.s L_0047
    L_0047: ldloc.1 
    L_0048: ret 
}

请注意,这些是方法调用正常呼叫的说明。该lambda表达式被转换成其他的方法,如:

Note that these are normal call instructions for the method calls. The lambdas get converted into other methods, such as:

[CompilerGenerated]
private static bool <ProductNames>b__2(Product p)
{
    return ((p.Id > 100) && (p.Id < 0x1388));
}

这篇关于什么是LINQ其实编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆