LINQ如何在内部工作?

时间:2009-03-22 16:23:45

标签: linq

我喜欢在.net上使用LINQ,但我想知道它在内部是如何工作的?

有谁知道吗?

THKS。

5 个答案:

答案 0 :(得分:79)

询问LINQ的特定方面更有意义。这有点像问“如何运作Windows”。

从C#的角度来看,LINQ的关键部分对我来说是

  • 表达树。这些是代码作为数据的表示。例如,表达式树可以表示“获取字符串参数,在其上调用Length属性并返回结果”的概念。这些存在为 data 而不是编译代码的事实意味着LINQ提供程序(如LINQ to SQL)可以分析它们并将它们转换为SQL。
  • Lambda表达式。这些是这样的表达式:

    x => x * 2
    (int x, int y) => x * y
    () => { Console.WriteLine("Block"); Console.WriteLine("Lambda"); }
    

    Lambda表达式转换为委托表达式树

  • 匿名类型。这些是这样的表达式:

    new { X=10, Y=20 }
    

    这些仍然是静态类型的,只是编译器为您生成具有属性XY的不可变类型。这些通常与var一起使用,它允许从其初始化表达式推断出局部变量的类型。

  • 查询表达式。这些是这样的表达式:

    from person in people
    where person.Age < 18
    select person.Name
    

    这些由C#编译器转换为“普通”C#3.0(即不使用查询表达式的表单)。之后应用重载分辨率等,这对于能够使用具有多种数据类型的相同查询语法是绝对关键的,而编译器不具有诸如Queryable之类的任何类型的知识。上述表达式将翻译成:

    people.Where(person => person.Age < 18)
          .Select(person => person.Name)
    
  • 扩展方法。这些是静态方法,可以像使用第一个参数类型的实例方法一样使用。例如,像这样的扩展方法:

    public static int CountAsciiDigits(this string text)
    {
        return text.Count(letter => letter >= '0' && letter <= '9');
    }
    
    然后可以像这样使用

    string foo = "123abc456";
    int count = foo.CountAsciiDigits();
    

    请注意,CountAsciiDigits的实施使用了另一种扩展方法Enumerable.Count()

这是大多数相关的语言方面。然后是LINQ提供程序中的标准查询运算符的实现,例如LINQ to Objects和LINQ to SQL等。我有一个关于如何实现LINQ to Objects的相当简单的演示文稿 - 它位于"Talks"页面上深度网站上的C#。

LINQ to SQL等提供程序的工作方式通常是通过Queryable类。他们的核心是将表达式树转换为其他查询格式,然后使用执行这些进程外查询的结果构造适当的对象。

这涵盖了您感兴趣的一切吗?如果有什么特别的东西你仍然想知道,只需编辑你的问题,我就可以去了。

答案 1 :(得分:5)

LINQ基本上是这些C#3.0离散功能的组合:

  • 局部变量类型推断
  • 自动属性(未在VB 9.0中实现)
  • 扩展方法
  • lambda expressions
  • 匿名类型初始化程序
  • 查询理解

有关到达目的地的更多信息(LINQ),请参阅LANGNET 2008中Anders的视频:

http://download.microsoft.com/download/c/e/5/ce5434ca-4f54-42b1-81ea-7f5a72f3b1dd/1-01%20-%20CSharp3%20-%20Anders%20Hejlsberg.wmv

答案 2 :(得分:4)

在简单的表单中,编译器会将您的代码查询转换为一堆泛型类和调用。在下面,在Linq2Sql的情况下,使用DbCommand,DbDataReader等构造和执行动态SQL查询。

说你有:

var q = from x in dc.mytable select x;

它将转换为以下代码:

IQueryable<tbl_dir_office> q = 
    dc.mytable.Select<tbl_dir_office, tbl_dir_office>(
        Expression.Lambda<Func<mytable, mytable>>(
            exp = Expression.Parameter(typeof(mytable), "x"), 
            new ParameterExpression[] { exp }
        )
    );

许多泛型,巨大的开销。

答案 3 :(得分:1)

基本上,linq是一些语言工具(编译器)和一些框架扩展的混合体。因此,当您编写linq查询时,它们将使用适当的接口(如IQuerable)执行。另请注意,运行时在linq中没有任何作用。

但在简短的回答中很难对linq公正。我建议你读一些书来吸引自己。我不确定这本告诉你Linq内部的书,但Linq in Action给了你很好的帮助。

答案 4 :(得分:0)

我有一个小的C#程序,演示了在C#中实现LINQ。

class Program
{
    static void Main(string[] args)
    {
        //Eventhough we call the method here, it gets called ONLY when the for loop is executed
        var Cities = LinQFunction(new List<string>() { "Bangalore", "Mysore", "Coorg", "Tumkur", "Kerala", "TamilNadu" });

        //LinQFunction() gets callled now
        foreach(var city in Cities)
        {
            Console.WriteLine(city);
        }
    }

   //This function is called ONLY when the foreach loop iterates and gets the item from the collection
   static IEnumerable<string> LinQFunction(List<string> cities)
    {
        foreach (var item in cities)
        {
            //Return each 'item' at a time 
            yield return item;
        }
    }
}

使用适当的断点。