sintaxis - ¿Cómo funciona LINQ internamente?
linq to sql (5)
Me encanta usar LINQ en .net, pero me pregunto cómo funciona internamente.
¿Alguien sabe eso?
Thks.
Básicamente, linq es una mezcla de algunas funciones de lenguaje (compilador) y algunas extensiones de framework. 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 hacer 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 los internos de Linq, pero Linq en Acción le da una buena mano al respecto.
En una forma simple, el compilador toma su consulta de código y la convierte en un grupo de clases y llamadas genéricas. Debajo, en el caso de Linq2Sql, una consulta SQL dinámica se construye y ejecuta usando DbCommand, DbDataReader, etc.
Digamos que tienes:
var q = from x in dc.mytable select x;
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.
LINQ es básicamente una combinación de características discretas de C # 3.0 de estos:
- inferencia de tipo de variable local
- propiedades automáticas (no implementadas en VB 9.0)
- métodos de extensión
- expresiones lambda
- Inicializadores de tipo anónimos
- comprensión de consultas
Para obtener más información sobre el recorrido para llegar allí (LINQ), consulte este video de Anders en LANGNET 2008:
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;
}
}
}
Use puntos de interrupción apropiados.
Tiene más sentido preguntar sobre un aspecto particular de LINQ. Es como preguntar "Cómo funciona Windows".
Las partes clave de LINQ son para mí, 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 estos existan como datos en lugar de como código compilado significa que los proveedores de LINQ, como LINQ to SQL, pueden analizarlos y convertirlos en SQL.
Expresiones lambda Estas son expresiones como esta:
x => x * 2 (int x, int y) => x * y () => { Console.WriteLine("Block"); Console.WriteLine("Lambda"); }
Las expresiones de Lambda se convierten en delegados o árboles de expresiones .
Tipos anónimos Estas son expresiones como esta:
new { X=10, Y=20 }
Estos aún están tipados estáticamente, es solo que el compilador genera un tipo inmutable para usted con las propiedades
X
eY
Estos se usan generalmente convar
que permite inferir el tipo de una 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 se traducen por el compilador de C # en C # 3.0 "normal" (es decir, un formulario que no utiliza expresiones de consulta). 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 en:
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 como este:
public static int CountAsciiDigits(this string text) { return text.Count(letter => letter >= ''0'' && letter <= ''9''); }
puede usarse así:
string foo = "123abc456"; int count = foo.CountAsciiDigits();
Tenga en cuenta que la implementación de
CountAsciiDigits
usa otro método de extensión,Enumerable.Count()
.
Esa es la mayoría de los aspectos lingüísticos relevantes. Luego están las implementaciones de los operadores de consulta estándar, en proveedores LINQ tales 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 el sitio web de profundidad.
La forma en que los proveedores como LINQ to SQL funcionan 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 te interesaba? Si hay algo en particular que aún quieres saber, solo edita tu pregunta y voy a probar.