2009-03-22 42 views
49

Me encanta usar LINQ en .net, pero me pregunto cómo funciona internamente.¿Cómo funciona LINQ internamente?

¿Alguien sabe eso?

Thks.

+6

Considera comprar el libro de John Skeet C# en profundidad –

+0

C# 3.0 en pocas palabras también es bueno. –

+1

Leí un tercio de [Linq en acción] [1] y es un gran libro. [1]: http://www.manning.com/marguerie/ –

Respuesta

76

Tiene más sentido para preguntar sobre un aspecto particular de LINQ. Es como preguntar "Cómo funciona Windows".

Las partes clave de LINQ para mí son, desde una perspectiva de C#:

  • árboles de expresión. Estas son representaciones de código como datos. Por ejemplo, un árbol de expresiones podría representar la noción de "tomar un parámetro de cadena, llamar a la propiedad Length en él y devolver el resultado". El hecho de que existan como datos en lugar de como código compilado significa que los proveedores de LINQ como LINQ to SQL pueden analizarlos y convertirlos a SQL.
  • Lambda expressions.Estas son expresiones como esta:

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

    expresiones lambda se convierten en cualquiera de los dos delegados o árboles de expresión.

  • Tipos anónimos. Estas son expresiones como esta:

    new { X=10, Y=20 } 
    

    Estos todavía se escriben de forma estática, es sólo el compilador genera un tipo inmutable para usted con propiedades X y Y. Suelen utilizarse con var, lo que permite inferir el tipo de variable local a partir de su expresión de inicialización.

  • Expresiones de consulta. Estas son expresiones como esta:

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

    Estos son traducidos por el compilador de C# en C# 3.0 (es decir, una forma que no utiliza expresiones de consulta) "normal". La resolución de sobrecarga, etc. se aplica después, lo cual es absolutamente clave para poder usar la misma sintaxis de consulta con múltiples tipos de datos, sin que el compilador tenga conocimiento de tipos como Queryable. La expresión anterior se traduciría a:

    people.Where(person => person.Age < 18) 
         .Select(person => person.Name) 
    
  • Métodos de extensión. Estos son métodos estáticos que se pueden usar como si fueran métodos de instancia del tipo del primer parámetro. Por ejemplo, un método de extensión de esta manera:

    public static int CountAsciiDigits(this string text) 
    { 
        return text.Count(letter => letter >= '0' && letter <= '9'); 
    } 
    

    puede entonces ser utilizado como esto:

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

    Nota que la aplicación de CountAsciiDigits utiliza otro método de extensión, Enumerable.Count().

Esa es la mayor parte de los idioma aspectos relevantes. Luego están las implementaciones de los operadores de consulta estándar, en proveedores de LINQ como LINQ to Objects y LINQ to SQL, etc. Tengo una presentación sobre cómo es razonablemente simple implementar LINQ to Objects - está en la página "Talks" de C# en profundidad sitio web

La forma en que operan los proveedores como LINQ to SQL es generalmente a través de la clase Queryable. En esencia, ellos traducen árboles de expresión en otros formatos de consulta, y luego construyen objetos apropiados con los resultados de ejecutar esas consultas fuera del proceso.

¿Eso cubre todo lo que le interese? Si hay algo en particular que aún quieres saber, solo edita tu pregunta y voy a probar.

+0

@JonSkeet Agregaría genéricos (y escriba inferencia y 'var') a los aspectos clave que hacen que linq sea posible ... – nawfal

+0

@nawfal: Ya tengo' var' en "tipos anónimos" - y aunque los genéricos son necesarios, ya eran parte de C# 2 y se usaban ampliamente fuera de LINQ. Si vamos a enumerar * todo * requerido, eso debería incluir "acceso a la propiedad" y "variables", etc. –

+0

@JonSkeet 'var' merece una mención fuera de los tipos anónimos, porque hubiera sido un desvío a escriba 'IOrderedEnumerable ' etc., de igual forma escriba inference. Hmmm, personalmente creo que los genéricos (aunque vinieron antes) difieren poco del acceso a la propiedad cuando se trata de su utilidad en linq, ymmv. – nawfal

1

Básicamente, linq es una mezcla de algunas funciones de lenguaje (compilador) y algunas extensiones de marco. Por lo tanto, cuando escribe consultas de linq, se ejecutan usando interfaces apropiadas como IQuerable. También tenga en cuenta que el tiempo de ejecución no tiene ningún rol en linq.

Pero es difícil hacerle justicia a linq en una respuesta corta. Te recomiendo que leas un libro para ponerte en él. No estoy seguro sobre el libro que le dice a internos de Linq pero Linq in Action da un buen handson sobre él.

4

En una forma simple, el compilador toma su consulta de código y la convierte en un grupo de clases y llamadas genéricas. Por debajo, en el caso de Linq2Sql, una consulta SQL dinámico se construye y se ejecuta mediante DbCommand, etc. DbDataReader

Digamos que tienes:

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

que se convierte en el siguiente código:

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 } 
     ) 
    ); 

Muchos genéricos, enormes gastos generales.

+1

Enorme sobrecarga? ¿Qué quieres decir? –

+0

El Seleccionar sobre terminará llamando al método de ejecución de un proveedor, que inicia el modo, determina la conexión, verifica las transacciones, inicia las colecciones de parámetros, llama a un lector, traduce los resultados, analiza ... miles de líneas. – Ruslan

+2

@Ruslan, casi todas las cosas que mencionaste tienen que hacer de todos modos para que no se consideren gastos indirectos, y además, verificar algunas cosas como si hay una transacción adjunta tiene un costo pequeño en comparación con ejecutar el comando en la base de datos. –

4

LINQ es básicamente una combinación de C# 3.0 características discretas de estos:

  • tipo variable local inferencia
  • propiedades de automóviles (no implementado en VB 9.0)
  • métodos de extensión
  • expresiones lambda
  • inicializadores de tipo anónimo
  • comprensión de la consulta

Para obtener más información sobre el viaje para llegar allí (LINQ), ver el vídeo de Anders en LANGNET 2008:

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

+2

Las propiedades automáticas no juegan un papel en LINQ y no están en VB9. –

+0

Sí, tienes razón, VB 9.0 no lo tiene. Editaré mi respuesta. –

+1

Creo que te perdiste el punto principal de que las propiedades automáticas no tienen nada que ver con LINQ. –

0

Tengo un pequeño programa de C# que demuestra la implementación de LINQ en C#.

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; 
     } 
    } 
} 

Utilice los puntos de interrupción apropiados.

Cuestiones relacionadas