2009-03-22 26 views
49

Mi piace usare LINQ su .net, ma mi chiedo di sapere come funziona internamente?In che modo LINQ funziona internamente?

Qualcuno lo sa?

Thks.

+6

Considerare l'acquisto del libro C# di John Skeet in profondità –

+0

C# 3.0 in breve è anche un bene. –

+1

Ho letto un terzo di [Linq in Action] [1] ed è un ottimo libro. [1]: http://www.manning.com/marguerie/ –

risposta

76

Ha più senso per chiedere di un particolare aspetto della LINQ. È un po 'come chiedere "Come funziona Windows" in caso contrario.

La parte fondamentale di LINQ sono per me, dal punto di vista C#:

  • alberi di espressione. Queste sono rappresentazioni del codice come dati. Ad esempio, un albero di espressioni potrebbe rappresentare la nozione di "prendere un parametro stringa, chiamare la proprietà Length su di esso e restituire il risultato". Il fatto che esistano come dati anziché come codice compilato significa che i provider LINQ come LINQ to SQL possono analizzarli e convertirli in SQL.
  • espressioni Lambda.Si tratta di espressioni come questa:

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

    lambda espressioni vengono convertite sia in delegati o alberi di espressione.

  • Tipi anonimi. Si tratta di espressioni come questa:

    new { X=10, Y=20 } 
    

    Questi sono ancora tipizzati staticamente, è solo il compilatore genera un tipo immutabile, per voi con le proprietà X e Y. Questi sono in genere utilizzati con var che consente di determinare il tipo di una variabile locale dalla sua espressione di inizializzazione.

  • Espressioni di query. Si tratta di espressioni come questa:

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

    presentate tradotti dal compilatore C# in "normale" C# 3.0 (vale a dire una forma che non fa uso di espressioni di query). La risoluzione di sovraccarico, ecc., Viene applicata in seguito, il che è assolutamente fondamentale per poter utilizzare la stessa sintassi di query con più tipi di dati, senza che il compilatore abbia alcuna conoscenza di tipi come Queryable. L'espressione sopra sarebbe tradotta in:

    people.Where(person => person.Age < 18) 
         .Select(person => person.Name) 
    
  • Metodi di estensione. Questi sono metodi statici che possono essere utilizzati come se fossero metodi di istanza del tipo del primo parametro. Ad esempio, un metodo di estensione simili:

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

    può quindi essere usato in questo modo:

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

    noti che l'esecuzione del CountAsciiDigits usa un altro metodo di estensione, Enumerable.Count().

che è più delle pertinenti lingua aspetti. Poi ci sono le implementazioni degli operatori di query standard, nei provider LINQ come LINQ to Objects e LINQ to SQL ecc. Ho una presentazione su come sia ragionevolmente semplice implementare LINQ to Objects: è nella pagina "Talks" del C# in Depth sito web.

Il modo in cui i provider LINQ a SQL funzionano è generalmente tramite la classe Queryable. Al loro interno, traducono gli alberi di espressione in altri formati di query e quindi costruiscono oggetti appropriati con i risultati dell'esecuzione di tali query out-of-process.

Questo copre tutto ciò che ti interessa? Se c'è qualcosa in particolare che vuoi ancora sapere, modifica la tua domanda e io avrò un tentativo.

+0

@JonSkeet Vorrei aggiungere generici (e digitare inferenza e 'var') per gli aspetti chiave che rendono possibile linq .. – nawfal

+0

@nawfal: ho' var' già sotto "tipi anonimi" - e mentre i generici sono necessari, erano già parte del C# 2 e ampiamente utilizzati al di fuori di LINQ. Se vogliamo elencare * tutto * richiesto, che dovrebbe includere "accesso alla proprietà" e "variabili" ecc. –

+0

@JonSkeet "var" merita una menzione al di fuori dei tipi anonimi, perché sarebbe stato un passaggio a scrivere 'IOrderedEnumerable ' etc, analogamente digitare inferenza. Hmmm, personalmente ritengo che i generici (anche se sono venuti prima) sono poco diversi dall'accesso alla proprietà quando si tratta della sua utilità in linq, ymmv. – nawfal

1

Fondamentalmente linq è una combinazione di alcune funzionalità linguistiche (compilatore) e alcune estensioni di framework. Quindi, quando si scrivono query di linq, vengono eseguite utilizzando interfacce appropriate come IQuerable. Si noti inoltre che il runtime non ha alcun ruolo in linq.

Ma è difficile rendere giustizia a linq in una risposta breve. Ti consiglio di leggere qualche libro per farti entrare. Non sono sicuro del libro che ti dice gli interni di Linq, ma lo standard Linq in Action ti dà una buona idea.

4

In un semplice modulo, il compilatore accetta la query sul codice e la converte in un gruppo di classi e chiamate generiche. Sotto, in caso di Linq2Sql, una query SQL dinamico viene costruito ed eseguito utilizzando DbCommand, DbDataReader ecc

Diciamo che avete:

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

esso viene convertito in codice seguente:

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

Un sacco di generici, enormi spese generali.

+1

Overhead enorme? cosa intendi? –

+0

Il Select about finirà per chiamare il metodo execute di un provider, quale modalità di inizializzazione, determinare la connessione, controllare le transazioni, inizializzare le collezioni di parametri, chiamare un lettore, tradurre risultati, analizzare ... migliaia di righe. – Ruslan

+2

@Ruslan, quasi tutte le cose che hai menzionato devi fare comunque in modo che non siano considerate overhead, e inoltre, controllare alcune cose come se ci sia una transazione collegata ha un costo molto piccolo rispetto all'esecuzione del comando sul DB. –

4

LINQ è fondamentalmente una combinazione di C# 3.0 caratteristiche discrete di questi:

  • tipo variabile locale proprietà auto inferenza
  • (non implementato in VB 9.0)
  • metodi di estensione
  • espressioni lambda
  • iniziatori di tipo anonimo
  • comprensione della domanda

Per ulteriori informazioni sul viaggio per arrivarci (LINQ), vedere questo video di Anders in LANGNET 2008:

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

+2

Le proprietà automatiche non hanno alcun ruolo in LINQ e non sono in VB9. –

+0

Sì, hai ragione, VB 9.0 non ce l'ha. Modificherò la mia risposta. –

+1

Penso che ti sia mancato il punto principale che le proprietà auto non hanno nulla a che fare con LINQ. –

0

Ho un piccolo programma C# che dimostra l'implementazione di LINQ in 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; 
     } 
    } 
} 

Utilizzare punti di interruzione appropriati.

Problemi correlati