Qual è l'aspetto più difficile o incompreso di LINQ? [chiuso]


282

Antefatto: nel prossimo mese, terrò tre discorsi o almeno LINQnel contesto di C#. Mi piacerebbe sapere a quali argomenti vale la pena prestare una buona dose di attenzione, in base a ciò che le persone possono trovare difficili da capire, o di cosa potrebbero avere un'impressione sbagliata. Non parlerò in modo specifico LINQdi SQLEntity Framework o di Entity tranne che come esempi di come le query possono essere eseguite in remoto usando gli alberi delle espressioni (e di solito IQueryable).

Quindi, cosa hai trovato difficile LINQ? Cosa hai visto in termini di incomprensioni? Gli esempi potrebbero essere i seguenti, ma per favore non limitarti!

  • Come il C#compilatore tratta le espressioni di query
  • Espressioni Lambda
  • Alberi di espressione
  • Metodi di estensione
  • Tipi anonimi
  • IQueryable
  • Esecuzione differita vs esecuzione immediata
  • Streaming vs esecuzione con buffer (ad es. OrderBy è differito ma con buffer)
  • Variabili locali tipizzate implicitamente
  • Lettura di firme generiche complesse (ad es. Enumerable.Join )

3
Sarei interessato a sapere quando farai questi colloqui, e se c'è modo di vederli online
Mark Heath,

2
Primo discorso: Copenaghen, 30 ottobre. Spero che questo sarà registrato. (Intera giornata!) Secondo discorso: Londra, 19 novembre sera, London .NET Users Group, probabilmente su Push LINQ. Terza conferenza: Lettura, 22 novembre, Developer Developer Day, Implementazione di LINQ to Objects in 60 minuti.
Jon Skeet,

1
Downvoter: si prega di aggiungere un commento esplicativo.
Jon Skeet,

2
@Jon, mi dispiace, ma devo chiudere questo.
Tim Post

3
@Tim: Abbastanza giusto - comunque non stava ottenendo più risposte. Personalmente penso che ha fatto finire per essere costruttiva, ti dispiacerebbe - ho certamente trovato utile per vedere che cosa la gente trova difficile. Probabilmente non l'avrei chiesto ora però ...
Jon Skeet,

Risposte:


271

Esecuzione ritardata


12
Righto: questo è chiaramente il preferito dai lettori, che è la cosa più importante per questa domanda. Aggiungerò anche "buffering vs streaming" nel mix, poiché è strettamente correlato - e spesso non è discusso in tutti i dettagli che mi piacerebbe vedere nei libri.
Jon Skeet,

10
Veramente? Ho avuto la natura pigra che mi è stata segnalata così tante volte mentre imparavo Linq, non è mai stato un problema per me.
Adam Lassek,

26
D'accordo con ALassek. La documentazione MSDN indica chiaramente la natura di valutazione pigra di LINQ. Forse il vero problema è la natura pigra della programmazione degli sviluppatori ... =)
Seiti,

4
... soprattutto quando ti rendi conto che si applica a LINQ per gli oggetti e non solo per LINQ 2 SQL: quando vedi 10 chiamate al metodo web per recuperare un elenco di elementi quando stai già enumerando lo stesso elenco di elementi e hai pensato che l'elenco è già stato valutato
Simon_Weaver,

5
Conoscere cos'è la dichiarazione di rendimento e come funziona è fondamentale per la comprensione approfondita di LINQ.
peSHIr

125

So che il concetto di esecuzione differita dovrebbe essere battuto in me ormai, ma questo esempio mi ha davvero aiutato a comprenderlo pratico:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

Il codice sopra riportato restituisce quanto segue:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory

2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- Penso che questo sia il miglior blog per spiegarlo secondo me. (lontano dal 2007, non riesco a credere che sia già in circolazione da così tanto tempo)
Phill

104

Che ci sia più di un semplice LINQper SQLe le caratteristiche sono molto più di un SQLparser incorporato nella lingua.


6
Sono stufo di tutti che pensano che: /
TraumaPony,

40
Non tutti lo fanno! Non so ancora cosa sia LINQ to SQL e uso LINQ per tutto il tempo.
Robert Rossney,

2
Sono così seccato quando provo a spiegare qualcosa usando LINQ e l'altra persona mi guarda e dice "ohhh non uso LINQ per niente del genere, solo SQL" :(
Nathan W,

13
D'accordo, molte persone non sembrano capire che LINQ sia uno strumento di uso generale.
Matthew Olenik,

86

Notazione O grande . LINQ rende incredibilmente facile scrivere algoritmi O (n ^ 4) senza accorgersene, se non sai cosa stai facendo.


16
Che ne dici di un esempio?
Hughdbrown,

4
Per quanto riguarda un esempio, forse intende il fatto che è molto facile avere una clausola Select che contenga molti operatori Sum () con ciascuno di essi che provoca un altro passaggio sull'intero recordset.
Rob Packwood

1
In effetti, potrebbe anche valere la pena esaminare ciò che è la grande notazione O e perché è importante, così come alcuni esempi di query risultanti inefficienti. Penso che sia quello che il poster originale stava suggerendo, ma ho pensato di menzionarlo comunque. - EDIT: appena realizzato che questo post aveva 1,5 anni :-)
zcrar70

7
Non sarebbe O (n ^ x), sarebbe O (xn), che è solo O (n).
Malfist,

3
Tentare di eseguire un join senza l'operatore di join comporterà O (n ^ x): da i1 nell'intervallo1 da i2 nell'intervallo2 da i3 nell'intervallo3 da i4 nell'intervallo4 dove i1 == i2 && i3 == i4 seleziona nuovo {i1, i2, i3, i4}. E ho già visto questo scritto prima. Funziona, ma molto lentamente.
MarkPflug

55

Penso che Lambdaun'espressione possa risolversi sia in un albero delle espressioni che in un delegato anonimo, quindi puoi trasmettere la stessa lambdaespressione dichiarativa sia ai IEnumerable<T>metodi di IQueryable<T>estensione che ai metodi di estensione.


2
Concordato. Sono un veterano e mi sono appena reso conto che questo casting implicito stava avvenendo mentre iniziavo a scrivere il mio QueryProvider
TheSoftwareJedi

53

Mi ha portato via troppo tempo per rendersi conto che molti metodi di estensione LINQ, come Single(), SingleOrDefault()ecc hanno sovraccarichi che prendono lambda.

Tu puoi fare :

Single(x => x.id == id)

e non c'è bisogno di dirlo - che qualche brutto tutorial mi ha preso l'abitudine di fare

Where(x => x.id == id).Single()

+1, molto carino. Lo terrò a mente.
Pretzel,

4
Continuo a dimenticare anche questo. È anche vero Count(), tra gli altri. Sai se c'è qualche differenza di prestazioni, oltre all'ovvio bonus della leggibilità del codice?
Justin Morgan,

1
All'università, il mio docente voleva decollare punti per l'utilizzo di questi sovraccarichi !! Gli ho dimostrato che si sbaglia!
TDaver,

12
Può sembrare strano ma preferisco la seconda sintassi. Lo trovo più leggibile.
Konamiman,

40

In LINQ to SQL vedo costantemente persone che non comprendono DataContext, come può essere usato e come dovrebbe essere usato. Troppe persone non vedono DataContext per quello che è, un oggetto Unit of Work, non un oggetto persistente.

Ho visto un sacco di volte in cui le persone stanno cercando di singleton un DataContext / session it / etc piuttosto che fare un nuovo tempo per ogni operazione.

E poi c'è lo smaltimento di DataContext prima che IQueryable sia stato valutato, ma è più di una ragione con persone che non capiscono IQueryable di DataContext.

L'altro concetto con cui vedo molta confusione è Query Syntax vs Expression Syntax. Userò quale mai è il più semplice a quel punto, spesso attenendosi alla sintassi di espressione. Molte persone ancora non si rendono conto che alla fine produrranno la stessa cosa, dopo tutto la query viene compilata in Expression.


2
Avvertenza: l'unità di lavoro può essere un piccolo programma con il contesto dei dati come singleton.
graffic,

15
Non utilizzare DataContext in un singleton, non è thread-safe.
Aaron Powell,

3
@Slace, non tutti i programmi sono multithead, quindi è OK avere DataContext come singleton in un sacco di software "desktop"
Ian Ringrose

2
Sono stato morso da questo (usando DataContext come singleton) quando ho realizzato il mio primo progetto LINQ to SQL. Non penso che la documentazione e i libri lo rendano abbastanza ovvio. In realtà, penso che il nome potrebbe essere migliorato, ma non sono sicuro di come.
Roger Lipscombe,

1
Ho impiegato più volte a leggere le opere di ScottGu su Linq per farmi battere in testa.
Evan Plaice,

34

Penso che la parte incompresa di LINQ sia che si tratta di un'estensione del linguaggio , non di un'estensione o di un costrutto di database.

LINQè molto più di LINQ to SQL.

Ora che la maggior parte di noi ha utilizzato le LINQcollezioni, non torneremo MAI più indietro!

LINQ è la caratteristica più significativa per .NET da Generics in 2.0 e Tipi anonimi in 3.0.

E ora che abbiamo Lambda, non vedo l'ora di programmare in parallelo!


Lo definirei anche più significativo dei tipi anonimi, e forse anche più dei generici.
Justin Morgan,

26

Personalmente vorrei sapere se ho bisogno di sapere quali sono gli alberi delle espressioni e perché.


6
Penso che valga la pena sapere quali sono gli alberi di espressione e perché esistono, ma non i dettagli su come costruirli da soli. (Sono un dolore da costruire a mano, ma il compilatore farà un ottimo lavoro quando converte un'espressione lambda.)
Jon Skeet,

3
In realtà, stavo pensando di fare qualche post sul blog sugli alberi delle espressioni (dato che li "capisco"). Trovo molto utile manipolare gli alberi delle espressioni ...
Marc Gravell

Tuttavia, non penso che siano utili per i discorsi di Jon ;-p
Marc Gravell

3
Temo solo che gli alberi delle espressioni saranno come la dichiarazione di rendimento: qualcosa che si è rivelato incredibilmente prezioso nonostante il fatto che all'inizio non ho capito a cosa servisse.
Robert Rossney,

1
Marc Gravell Mi piacerebbe leggere le voci del tuo blog sull'argomento. Non vedo l'ora
Alexandre Brisebois,

20

Sono abbastanza nuovo in LINQ. Ecco le cose su cui sono inciampato nel mio primo tentativo

  • Combinazione di più query in una
  • Effettuare il debug efficace delle query LINQ in Visual Studio.

21
Il debug di LINQ è un argomento a sé stante e importante. Penso che la più grande debolezza di LINQ sia che ti consente di scrivere blocchi di logica arbitrariamente complessa che non puoi superare.
Robert Rossney,

3
questi possono essere un buon posto per usare il pad LINQ
Maslow

2
Sono d'accordo di cuore; ecco perché ho scritto LINQ Secrets Revealed: Chaining and Debugging , appena pubblicato su Simple-Talk.com, che potresti trovare di aiuto.
Michael Sorens,

Sì, LinqPad è un ottimo strumento secondario per lo sviluppo delle tue query LINQ. Soprattutto quando inizi e sei nuovo alle convenzioni / schemi.
Buffalo,

20

Qualcosa che inizialmente non mi ero reso conto era che la sintassi LINQ non richiede IEnumerable<T>o nonIQueryable<T> funziona, LINQ riguarda solo la corrispondenza dei modelli.

testo alternativo http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Ecco la risposta (no, non ho scritto quel blog, Bart De Smet, ed è uno dei migliori blogger su LINQ che ho trovato).


1
Potresti trovare interessante anche questo post sul blog: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet,

Bel post Jon (mi iscrivo al tuo blog, solo di recente però).
Aaron Powell,

19

Ho ancora problemi con il comando "let" (per cui non ho mai trovato un uso) e SelectMany (che ho usato, ma non sono sicuro di averlo fatto bene)


2
Ogni volta che vuoi introdurre una variabile dovresti usare un'istruzione let. Pensa a un ciclo tradizionale in cui stai introducendo variabili al suo interno e dando a ogni variabile un nome per aiutare la leggibilità del codice. A volte è anche bello avere un'istruzione let che valuta un risultato di funzione, che è quindi possibile selezionare e ordinare in base a senza dover valutare il risultato due volte.
Rob Packwood

'let' ti permette di fare tipi compositi. Cose pratiche.
Phill,

19

Comprendere quando perde l'astrazione tra i fornitori di Linq. Alcune cose funzionano su oggetti ma non su SQL (ad es. .TakeWhile). Alcuni metodi possono essere tradotti in SQL (ToUpper) mentre altri no. Alcune tecniche sono più efficienti negli oggetti in cui altre sono più efficaci in SQL (diversi metodi di join).


1
Questo è un ottimo punto. Non aiuta che Intellisense ti mostri TUTTI e di solito si compila. Quindi esplodi in fase di esecuzione. Spero che VS 2010 faccia un lavoro migliore nel mostrare i metodi di estensione pertinenti.
Jason Short,

12

Un paio di cose.

  1. La gente pensa a Linq come Linq a SQL.
  2. Alcune persone pensano di poter iniziare a sostituire tutte le operazioni foreach / logic con le query Linq senza considerare queste implicazioni sulle prestazioni.

11

OK, a causa della domanda, ho scritto alcune delle cose di Expression. Non sono soddisfatto al 100% di come blogger e LiveWriter abbiano cospirato per formattarlo, ma per ora lo farà ...

Ad ogni modo, qui va ... Mi piacerebbe qualsiasi feedback, soprattutto se ci sono aree in cui le persone vogliono maggiori informazioni.

Eccolo , piace o odio ...


10

Alcuni dei messaggi di errore, in particolare da LINQ a SQL, possono essere piuttosto confusi. sorriso

Sono stato morso dall'esecuzione differita un paio di volte come tutti gli altri. Penso che la cosa più confusa per me sia stata il provider di query di SQL Server e ciò che puoi e non puoi farci.

Sono ancora sorpreso dal fatto che non puoi fare una somma () su una colonna decimale / denaro che a volte è vuota. L'uso di DefaultIfEmpty () non funzionerà. :(


1
Prete facile da schiaffeggiare un Where on quella query per far funzionare la somma
Esben Skov Pedersen,

9

Penso che una cosa grandiosa da affrontare in LINQ sia come mettersi nei guai in termini di prestazioni. Ad esempio, l'utilizzo del conteggio di LINQ come condizione di loop non è davvero intelligente.


7

Che IQueryable accetta entrambi Expression<Func<T1, T2, T3, ...>>eFunc<T1, T2, T3, ...> , senza dare un accenno al degrado delle prestazioni nel secondo caso.

Ecco un esempio di codice che dimostra cosa intendo:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}

Puoi spiegare? Non sto seguendo ...
Pretzel,

@Pretzel Ho aggiunto un esempio di codice che dimostra il mio problema.
Valera Kolupaev,

Grazie per l'esempio di codice! Molto utile.
Buffalo,

6

Non so se si qualifichi come frainteso - ma per me, semplicemente sconosciuto.

Mi ha fatto piacere conoscere DataLoadOptions e come posso controllare quali tabelle vengono unite quando eseguo una query specifica.

Vedi qui per maggiori informazioni: MSDN: DataLoadOptions


6

Direi che l'aspetto più incompreso (o che non dovrebbe essere compreso?) Di LINQ è rappresentato dai provider LINQ IQueryable e personalizzati .

Sto usando LINQ da un po 'di tempo e sono completamente a mio agio nel mondo IEnumerable e posso risolvere la maggior parte dei problemi con LINQ.

Ma quando ho iniziato a guardare e leggere IQueryable, Expressions e fornitori di linq personalizzati mi ha fatto girare la testa. Dai un'occhiata a come funziona LINQ to SQL se vuoi vedere una logica piuttosto complessa.

Non vedo l'ora di capire quell'aspetto di LINQ ...


6

Come molte persone hanno detto, penso che la parte più fraintesa sia supporre che LINQ sia solo un sostituto di T-SQL. Il mio manager che si considera un guru di TSQL non ci permetterebbe di usare LINQ nel nostro progetto e odia persino la SM per aver rilasciato una cosa del genere !!!


Troppe persone lo usano come sostituto di TSQL. Molti di loro non hanno mai sentito parlare di un piano di esecuzione.
erikkallen,

+1 perché sono d'accordo con il tuo manager, almeno nella misura in cui consenti LINQ to SQL in qualsiasi progetto. LINQ to Objects è completamente un'altra questione.
NotMe

5

Cosa rappresenta var quando viene eseguita una query?

E ' iQueryable, iSingleResult, iMultipleResult, o lo fa cambia in base alla realizzazione. C'è qualche speculazione sull'uso (di ciò che sembra essere) di tipo dinamico rispetto a quello statico standard in C #.


AFAIK var è sempre la classe concreta in questione (anche se è un tipo anonimo) quindi non è mai IQueryable, ISingleResult o qualsiasi cosa che inizi con 'I' (non è necessario applicare le classi concrete che iniziano con 'I').
Motti,

5

Quanto sia facile nidificare un ciclo è qualcosa che non credo capiscano tutti.

Per esempio:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem

+1, whoa. è abbastanza potente.
Pretzel,

4

group by mi fa ancora girare la testa.

Qualsiasi confusione sull'esecuzione differita dovrebbe poter essere risolta esaminando un semplice codice basato su LINQ e giocando nella finestra di controllo.


1
Ho scoperto che implementare un bel po 'di LINQ su Oggetti per divertimento aiuta davvero :) Ma sì, è un po' confuso - certamente se non ho fatto LINQ per un po 'devo tornare alle firme. Allo stesso modo "unisciti" vs "unisciti a" spesso mi prende ...
Jon Skeet,

4

Query compilate

Il fatto che non si possa incatenare IQueryableperché sono chiamate di metodo (mentre ancora nient'altro che SQL traducibile!) E che è quasi impossibile aggirarlo è strabiliante e crea un'enorme violazione di DRY. Ho bisogno del mio IQueryablead-hoc in cui non ho compilato query (ho solo compilato query per gli scenari pesanti), ma nelle query compilate non posso usarle e invece devo scrivere di nuovo la sintassi delle query regolari. Ora sto eseguendo le stesse subquery in 2 posti, devo ricordare di aggiornare sia se qualcosa cambia, e così via. Un incubo.


4

Penso che l'idea sbagliata n. 1 su LINQ to SQL sia che DEVI ANCORA CONOSCERE SQL per poterne fare un uso efficace.

Un'altra cosa fraintesa su Linq to Sql è che devi ancora abbassare la sicurezza del tuo database al punto di assurdità per farlo funzionare.

Un terzo punto è che l'uso di Linq a SQL insieme alle classi dinamiche (il che significa che la definizione della classe viene creata in fase di esecuzione) provoca un'enorme quantità di compilazione just-in-time. Che può assolutamente uccidere le prestazioni.


4
Tuttavia, è molto utile conoscere già SQL. Alcuni SQL emessi da Linq su SQL (e altri ORM) possono essere decisamente dubbiosi e conoscere SQL aiuta a diagnosticare tali problemi. Inoltre, Linq to SQL può utilizzare le stored procedure.
Robert Harvey,


2

Come accennato, caricamento lento ed esecuzione differita

In che modo LINQ to Objects e LINQ to XML (IEnumerable) sono diversi da LINQ a SQL (IQueryable)

COME costruire un livello di accesso ai dati, un livello aziendale e un livello di presentazione con LINQ in tutti i livelli .... e un buon esempio.


I primi due che posso fare. Non vorrei provare a fare il terzo ancora nel senso "questo è il modo giusto di farlo" ...
Jon Skeet,

+1, fino a quando non lo hai sottolineato, non mi ero reso conto che LINQ-to-Objects e LINQ-to-XML erano IEnumerable rispetto a LINQ-to-SQL come IQueryable, ma ha senso. Grazie!
Pretzel,

2

Come molte persone hanno detto, penso che la parte più fraintesa sia supporre che LINQ sia solo un sostituto di T-SQL. Il mio manager che si considera un guru di TSQL non ci permetterebbe di usare LINQ nel nostro progetto e odia persino la SM per aver rilasciato una cosa del genere !!!


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.