Jaki jest najtrudniejszy lub najbardziej niezrozumiany aspekt LINQ? [Zamknięte]

282

Kontekst: W ciągu najbliższego miesiąca wygłosię trzy wykłady na temat lub przynajmniej LINQw kontekście C#. Chciałbym wiedzieć, na które tematy warto poświęcić sporo uwagi, w oparciu o to, co ludzie mogą mieć trudności z zrozumieniem lub na co mogą mieć błędne wrażenie. Nie będę mówić o specjalnie LINQdo SQLlub Entity Framework wyjątkiem przykładów jak Zapytania mogą być wykonywane zdalnie za pomocą wyrażenia drzew (zwykle IQueryable).

A więc, co ci tak trudno LINQ? Co widziałeś w kategoriach nieporozumień? Przykładami mogą być następujące, ale nie ograniczaj się!

  • Jak C#kompilator traktuje wyrażenia zapytania
  • Wyrażenia lambda
  • Drzewa ekspresji
  • Metody rozszerzenia
  • Anonimowe typy
  • IQueryable
  • Odroczone vs natychmiastowe wykonanie
  • Streaming vs buforowane wykonanie (np. OrderBy jest odroczony, ale buforowany)
  • Zmienne lokalne niejawnie wpisane
  • Odczytywanie złożonych podpisów ogólnych (np. Enumerable.Join )
Jon Skeet
źródło
3
Chciałbym wiedzieć, kiedy zamierzasz przeprowadzić te rozmowy, a jeśli jest jakiś sposób, aby zobaczyć je online
Mark Heath,
2
Pierwsza rozmowa: Kopenhaga, 30 października. Mam nadzieję, że zostanie to nagrane. (Cały dzień!) Druga rozmowa: Londyn, 19 listopada wieczorem, Londyńska grupa użytkowników .NET, prawdopodobnie na Push LINQ. Trzecia rozmowa: Reading, 22 listopada, Developer Developer Day, Implementacja LINQ do Objects w 60 minut.
Jon Skeet,
1
Downvoters: dodaj komentarz wyjaśniający.
Jon Skeet
2
@Jon, przepraszam, ale muszę to zamknąć.
Tim Post
3
@Tim: W porządku - i tak nie otrzymywał już więcej odpowiedzi. Osobiście myślę, że nie skończyć się konstruktywne, nic cię - Ja na pewno okazało się przydatne, aby zobaczyć, co ludzie uważają trudne. Prawdopodobnie nie zadałbym tego teraz ...
Jon Skeet,

Odpowiedzi:

271

Opóźnione wykonanie

JaredPar
źródło
12
Righto - to zdecydowanie ulubieniec czytelników, co jest najważniejsze w tym pytaniu. Dodam także „buforowanie vs streaming”, ponieważ jest to ściśle powiązane - i często nie jest omawiane tak szczegółowo, jak chciałbym zobaczyć w książkach.
Jon Skeet,
10
Naprawdę? Wielokrotnie zwracałem uwagę na to, że jego leniwa natura wskazywała mi podczas nauki Linq, że nigdy nie było to dla mnie problemem.
Adam Lassek,
26
Zgadzam się z ALassek. Dokumentacja MSDN wyraźnie określa leniwy charakter LINQ. Być może prawdziwym problemem jest leniwa natura programistów ... =)
Seiti,
4
... zwłaszcza, gdy zdasz sobie sprawę, że dotyczy to LINQ do obiektów, a nie tylko SQL LINQ 2 SQL - gdy zobaczysz 10 wywołań metod internetowych, aby pobrać listę elementów, gdy już wyliczasz tę samą listę elementów i pomyślałeś, że lista została już oceniona
Simon_Weaver
5
Wiedza o tym, co to jest deklaracja wydajności i jak ona działa, ma kluczowe znaczenie dla dokładnego zrozumienia LINQ.
peSHIr
125

Wiem, że koncepcja odroczonego wykonania powinna być do mnie teraz pobita, ale ten przykład naprawdę pomógł mi ją zrozumieć:

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

Powyższy kod zwraca następujące elementy:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory
DSO
źródło
2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- Myślę, że to najlepszy blog, który moim zdaniem to wyjaśni. (daleko w 2007 roku, nie mogę uwierzyć, że to już tak długo trwało)
Phill
104

Że istnieje więcej niż tylko LINQdo SQLi funkcje są czymś więcej niż tylko SQLparsera wbudowanych w język.

smaclell
źródło
6
Mam dość wszystkich, którzy myślą, że: /
TraumaPony
40
Nie wszyscy to robią! Nadal nie wiem, czym jest LINQ to SQL i używam LINQ przez cały cholerny czas.
Robert Rossney,
2
Tak się denerwuję, gdy próbuję wyjaśnić coś za pomocą LINQ, a druga osoba po prostu na mnie patrzy i mówi: „ohhh, nie używam LINQ do niczego takiego, tylko SQL” :(
Nathan W
13
Zgadzając się, wiele osób nie rozumie, że LINQ jest narzędziem ogólnego zastosowania.
Matthew Olenik
86

Notacji Big O . LINQ sprawia, że ​​niezwykle proste jest pisanie algorytmów O (n ^ 4) bez zdawania sobie z tego sprawy, jeśli nie wiesz, co robisz.

erikkallen
źródło
16
Co powiesz na przykład?
hughdbrown
4
Jako przykład, może on oznacza fakt, że bardzo łatwo jest mieć klauzulę Select zawierającą wiele operatorów Sum (), z których każdy powoduje kolejne przejście całego zestawu rekordów.
Rob Packwood,
1
W rzeczywistości warto nawet zastanowić się, czym jest duża notacja O i dlaczego jest ważna, a także kilka przykładów nieefektywnych wynikowych zapytań. Myślę, że to właśnie sugerował oryginalny plakat, ale pomyślałem, że i tak o tym wspomnę. - EDYCJA: właśnie zdałem sobie sprawę, że ten post miał 1,5 roku :-)
zcrar70
7
To nie byłoby O (n ^ x), to byłoby O (xn), co jest po prostu O (n).
Malfist
3
Próba wykonania łączenia bez operatora sprzężenia spowoduje O (n ^ x): od i1 w zakresie 1 od i2 w zakresie 2 od i3 w zakresie 3 od i4 w zakresie 4 gdzie i1 == i2 && i3 == i4 wybierz nowy {i1, i2, i3, i4}. I rzeczywiście widziałem to wcześniej. Działa, ale bardzo powoli.
MarkPflug
55

Myślę, że fakt, że Lambdawyrażenie może zostać rozpoznane zarówno w drzewie wyrażeń, jak i anonimowym uczestniku, możesz więc przekazać to samo lambdawyrażenie deklaratywne zarówno do IEnumerable<T>metod rozszerzenia, jak i IQueryable<T>metod rozszerzenia.

Tim Jarvis
źródło
2
Zgoda. Jestem weteranem i właśnie zdałem sobie sprawę, że ten niejawny casting miał miejsce, kiedy zacząłem pisać własnego QueryProvider
TheSoftwareJedi
53

Zabrał mnie sposób zbyt długo, aby uświadomić sobie, że wiele metod rozszerzeń LINQ takich jak Single(), SingleOrDefault()etc mieć przeciążeń, które biorą lambdy.

Możesz to zrobić :

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

i nie muszę tego mówić - co jakiś kiepski tutorial przyzwyczaił mnie robić

Where(x => x.id == id).Single()
Simon_Weaver
źródło
+1, bardzo miło. Zapamiętam to.
Precel
4
Też o tym zapominam. Dotyczy to również Count()m.in. Czy wiesz, czy jest jakaś różnica w wydajności oprócz oczywistej korzyści z czytelności kodu?
Justin Morgan
1
Na uniwersytecie mój wykładowca chciał zdjąć punkty za użycie tych przeciążeń !! Udowodniłem, że się myli!
TDaver
12
Może to zabrzmieć dziwnie, ale wolę drugą składnię. Uważam to za bardziej czytelne.
Konamiman
40

W LINQ to SQL ciągle widzę ludzi, którzy nie rozumieją DataContext, jak można go używać i jak należy go używać. Zbyt wiele osób nie widzi obiektu DataContext, ponieważ jest to obiekt jednostki pracy, a nie obiekt trwały.

Widziałem wiele razy, gdy ludzie próbowali singletować DataContext / session it / etc, zamiast tworzyć nowy czas dla każdej operacji.

A potem istnieje usuwanie DataContext przed oceną IQueryable, ale jest to raczej propozycja dla osób, które nie rozumieją IQueryable niż DataContext.

Inną koncepcją, z którą widzę wiele nieporozumień, jest składnia zapytań vs. składnia wyrażeń. Użyję tego, co w tej chwili jest najłatwiejsze, często pozostając przy składni wyrażeń. Wiele osób wciąż nie zdaje sobie sprawy z tego, że ostatecznie wyprodukują to samo, w końcu Query jest kompilowane w Expression.

Aaron Powell
źródło
2
Ostrzeżenie: Jednostka pracy może być małym programem z kontekstem danych jako singletonem.
graffic
15
Nie powinieneś używać DataContext w singletonie, nie jest on bezpieczny dla wątków.
Aaron Powell,
3
@Slace, nie wszystkie programy są wielogłowicowe, więc może być DataContext jako singleton w wielu „komputerowych” programach
Ian Ringrose,
2
Ugryzło mnie to (używając DataContext jako singletonu), kiedy wykonałem swój pierwszy projekt LINQ to SQL. Nie sądzę, że dokumentacja i książki czynią to wystarczająco oczywistym. Właściwie myślę, że nazwę można poprawić, ale nie jestem pewien, jak to zrobić.
Roger Lipscombe,
1
Wiele razy zajęło mi czytanie artykulów ScottGu na Linq, aby waliło mi się to w głowie.
Evan Plaice,
34

Myślę część niezrozumiany LINQ to, że jest to rozszerzenie języka , a nie rozszerzenie bazy danych lub konstrukt.

LINQjest o wiele więcej niż LINQ to SQL.

Teraz, gdy większość z nas korzysta LINQz kolekcji, NIGDY nie wrócimy!

LINQ jest najważniejszą cechą .NET od Generics w 2.0 i Anonimowych typów w 3.0.

A teraz, kiedy mamy Lambdę, nie mogę się doczekać programowania równoległego!

Chris
źródło
Nazwałbym to nawet bardziej znaczącym niż anonimowe typy, a być może nawet większym niż generyczne.
Justin Morgan
26

Na przykład chciałbym wiedzieć, czy muszę wiedzieć, jakie są drzewa wyrażeń i dlaczego.

Robert Rossney
źródło
6
Myślę, że warto wiedzieć, jakie są drzewa ekspresji i dlaczego one istnieją, ale nie szczegółowo, jak je samodzielnie zbudować. (Tworzenie kompilacji ręcznie jest trudne, ale kompilator wykona świetną robotę, konwertując wyrażenie lambda.)
Jon Skeet,
3
Właściwie to myślałem o zrobieniu kilku wpisów na blogach dotyczących drzew wyrażeń (ponieważ je „łapię”). Uważam, że manipulowanie drzewami wyrażeń jest bardzo przydatne ...
Marc Gravell
Jednak nie sądzę, aby były pomocne w rozmowach Jona ;-p
Marc Gravell
3
Martwię się tylko, że drzewa wyrażeń będą podobne do deklaracji plonu: coś, co okazało się niezwykle cenne, mimo że na początku nie rozumiałem, po co.
Robert Rossney,
1
Marc Gravell Chciałbym przeczytać twoje wpisy na blogu na ten temat. Nie możemy się już doczekać
Alexandre Brisebois,
20

Jestem dość nowy w LINQ. Oto rzeczy, na które natknąłem się podczas mojej pierwszej próby

  • Łączenie kilku zapytań w jedno
  • Skutecznie debuguje zapytania LINQ w Visual Studio.
Mark Heath
źródło
21
Debugowanie LINQ jest samo w sobie tematem ważnym. Myślę, że największą słabością LINQ jest to, że pozwala on pisać bloki o arbitralnie złożonej logice, których nie można przejść.
Robert Rossney,
3
mogą być dobrym miejscem do korzystania z padu LINQ
Maslow
2
Zgadzam się serdecznie; dlatego napisałem LINQ Secrets Revealed: Chains and Debugging , właśnie opublikowane na Simple-Talk.com, które możesz znaleźć jako pomoc.
Michael Sorens,
Tak, LinqPad jest doskonałym narzędziem pomocniczym do tworzenia zapytań LINQ. Zwłaszcza gdy zaczynasz i jesteś nowy w konwencjach / wzorach.
Buffalo,
20

Coś, czego początkowo nie zdawałem sobie sprawy, to to, że składnia LINQ nie wymaga IEnumerable<T>ani IQueryable<T>nie działa, LINQ polega tylko na dopasowaniu wzorców.

alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Oto odpowiedź (nie, nie napisałem tego bloga, zrobił to Bart De Smet i jest on jednym z najlepszych blogerów na LINQ, jaki znalazłem).

Aaron Powell
źródło
1
Interesujący może być również ten post na blogu: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet
Niezły post Jon (subskrybuję waszego bloga, jednak dopiero niedawno).
Aaron Powell,
19

Nadal mam problemy z poleceniem „let” (dla którego nigdy nie znalazłem zastosowania) i SelectMany (którego użyłem, ale nie jestem pewien, czy zrobiłem to dobrze)

James Curran
źródło
2
Za każdym razem, gdy chcesz wprowadzić zmienną, użyjesz instrukcji let. Pomyśl o tradycyjnej pętli, w której wprowadzasz do niej zmienne i nadajesz każdej zmiennej nazwę, aby poprawić czytelność kodu. Czasami miło jest również, gdy masz instrukcję let oceniającą wynik funkcji, którą możesz następnie wybrać i uporządkować bez konieczności dwukrotnej oceny wyniku.
Rob Packwood,
„let” pozwala tworzyć typy kompozytowe. Przydatne rzeczy.
Phill
19

Zrozumienie, kiedy przecieka abstrakcja wśród dostawców Linq. Niektóre rzeczy działają na obiektach, ale nie na SQL (np. .TakeWhile). Niektóre metody mogą zostać przetłumaczone na SQL (ToUpper), podczas gdy inne nie. Niektóre techniki są bardziej wydajne w obiektach, w których inne są bardziej skuteczne w SQL (różne metody łączenia).

Denis Phillips
źródło
1
To bardzo dobry punkt. Nie pomaga to, że Intellisense pokaże WSZYSTKIE z nich i zwykle nawet się skompiluje. Następnie wysadzasz w czasie działania. Mam nadzieję, że VS 2010 wykona lepszą pracę, pokazując odpowiednie metody rozszerzenia.
Jason Short,
12

Kilka rzeczy.

  1. Ludzie myślą o Linq jako o Linq na SQL.
  2. Niektóre osoby myślą, że mogą zacząć zastępować wszystkie foreach / logikę zapytaniami Linq bez uwzględnienia tego wpływu na wydajność.
Krishna Kumar
źródło
11

OK, z powodu popytu napisałem niektóre rzeczy z Expression. Nie jestem w 100% zadowolony z tego, jak blogger i LiveWriter spiskowali, aby go sformatować, ale na razie wystarczy ...

W każdym razie, proszę bardzo ... Chciałbym uzyskać wszelkie informacje zwrotne, szczególnie jeśli są obszary, w których ludzie chcą więcej informacji.

Oto jest , lubię to lub nienawidzę ...

Marc Gravell
źródło
10

Niektóre komunikaty o błędach, szczególnie od LINQ do SQL, mogą być dość mylące. szeroki uśmiech

Odgryzła mnie odroczona egzekucja kilka razy, jak wszyscy inni. Myślę, że najbardziej mylącą rzeczą był dla mnie SQL Server Query Provider i co możesz, a czego nie możesz zrobić.

Nadal jestem zdumiony faktem, że nie można wykonać Sum () na kolumnie dziesiętnej / pieniężnej, która czasami jest pusta. Korzystanie z DefaultIfEmpty () po prostu nie działa. :(

Per Erik Stendahl
źródło
1
Słyszę, że łatwo jest policzkować Gdzie w tym zapytaniu, aby suma zadziałała
Esben Skov Pedersen
9

Myślę, że świetną rzeczą do omówienia w LINQ jest to, jak możesz wpakować się w problemy z wydajnością. Na przykład użycie licznika LINQ jako warunku pętli jest naprawdę, naprawdę nie jest mądre.

Steve
źródło
7

To IQueryable akceptuje oba, Expression<Func<T1, T2, T3, ...>>i Func<T1, T2, T3, ...>bez wskazania spadku wydajności w drugim przypadku.

Oto przykład kodu, który pokazuje, co mam na myśli:

[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);
}
Valera Kolupaev
źródło
Możesz wytłumaczyć? Nie śledzę ...
Pretzel
@Pretzel Dodałem przykład kodu, który pokazuje mój problem.
Valera Kolupaev
Dzięki za przykład kodu! Bardzo pomocne.
Buffalo,
6

Nie wiem, czy można to uznać za niezrozumiane - ale dla mnie po prostu nieznane.

Z przyjemnością dowiedziałem się o DataLoadOptions i jak mogę kontrolować, które tabele są połączone, kiedy wykonuję określone zapytanie.

Zobacz tutaj, aby uzyskać więcej informacji: MSDN: DataLoadOptions

Jaskółka oknówka
źródło
6

Powiedziałbym, że najbardziej niezrozumianym (a może nie należy tego rozumieć?) Aspektem LINQ są IQueryable i niestandardowi dostawcy LINQ .

Od jakiegoś czasu korzystam z LINQ i czuję się całkowicie swobodnie w świecie IENumerable i mogę rozwiązać większość problemów z LINQ.

Ale kiedy zacząłem przeglądać i czytać o IQueryable oraz wyrażeniach i niestandardowych dostawcach linq, to ​​sprawiło, że zacząłem kręcić głową. Zobacz, jak działa LINQ to SQL, jeśli chcesz zobaczyć dość złożoną logikę.

Nie mogę się doczekać, aby zrozumieć ten aspekt LINQ ...

Jack Ukleja
źródło
6

Jak większość ludzi powiedziała, myślę, że najbardziej źle rozumiane jest założenie, że LINQ jest tylko zamiennikiem T-SQL. Mój menedżer, który uważa się za guru TSQL, nie pozwoli nam używać LINQ w naszym projekcie, a nawet nienawidzi MS za wydanie takiej rzeczy !!!

HashName
źródło
Zbyt wiele osób używa go jako zamiennika TSQL. Większość z nich nigdy nie słyszała o planie egzekucji.
erikkallen
+1, ponieważ zgadzam się z twoim menedżerem, przynajmniej w zakresie, w jakim zezwalam LINQ na SQL w dowolnym projekcie. LINQ to Objects to zupełnie inna sprawa.
NotMe
5

Co reprezentuje var, gdy zapytanie jest wykonywane?

Jest to iQueryable, iSingleResult, iMultipleResult, lub nie zmienia w zależności od implementacji. Istnieją pewne spekulacje na temat używania (jak się wydaje) pisania dynamicznego w porównaniu do standardowego pisania statycznego w języku C #.

user31939
źródło
AFAIK var zawsze jest konkretną klasą, o której mowa (nawet jeśli jest to typ anonimowy), więc nigdy nie jest IQueryable, ISingleResult lub cokolwiek zaczynającego się na „I” (konkretne klasy zaczynające się na „I” nie muszą mieć zastosowania).
Motti,
5

Jak łatwo jest zagnieździć pętlę, nie sądzę, że wszyscy ją rozumieją.

Na przykład:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
Rob Packwood
źródło
+1, whoa. to dość potężne.
Precel
4

group by wciąż kręci mi się w głowie.

Wszelkie nieporozumienia związane z odroczonym wykonywaniem powinny być rozwiązane przez przejście przez prosty kod oparty na LINQ i zabawę w oknie zegarka.

Richard Ev
źródło
1
Przekonałem się, że implementacja całkiem sporo LINQ do Objects dla zabawy naprawdę pomaga :) Ale tak, to jest trochę mylące - na pewno jeśli nie zrobiłem żadnego LINQ przez jakiś czas, muszę wrócić do podpisów. Podobnie „dołącz” do „dołącz do” często powoduje, że ...
Jon Skeet
4

Skompilowane zapytania

Fakt, że nie można łączyć w łańcuch, IQueryableponieważ są to wywołania metod (chociaż wciąż jest to tylko język SQL możliwy do przetłumaczenia!) I że jest prawie niemożliwe obejście tego, jest oszałamiający i powoduje ogromne naruszenie DRY. Potrzebuję moich IQueryablead-hoc, w których nie mam skompilowanych zapytań (mam tylko skompilowane zapytania dla ciężkich scenariuszy), ale w skompilowanych zapytaniach nie mogę ich użyć i zamiast tego muszę ponownie napisać regularną składnię zapytań. Teraz robię te same podkwerendy w 2 miejscach, muszę pamiętać, aby zaktualizować oba, jeśli coś się zmieni, i tak dalej. Koszmar.

Alex
źródło
4

Myślę, że # 1 nieporozumieniem na temat LINQ na SQL polega na tym, że MUSISZ WIEDZIEĆ o SQL, aby skutecznie z niego korzystać.

Kolejną niezrozumianą rzeczą dotyczącą Linq dla Sql jest to, że wciąż musisz obniżyć bezpieczeństwo bazy danych do absurdu, aby działało.

Trzecią kwestią jest to, że użycie Linq do Sql wraz z klasami Dynamic (co oznacza, że ​​definicja klasy jest tworzona w czasie wykonywania) powoduje ogromną ilość kompilacji just-in-time. Co może całkowicie zabić wydajność.

Nie ja
źródło
4
Jednak znajomość SQL jest bardzo korzystna. Niektóre SQL emitowane przez Linq do SQL (i innych ORM) mogą być wręcz wątpliwe, a znajomość SQL pomaga zdiagnozować takie problemy. Również Linq do SQL może korzystać z procedur przechowywanych.
Robert Harvey
2

Jak wspomniano, leniwe ładowanie i odroczenie wykonania

Czym LINQ do obiektów i LINQ do XML (IEnumerable) różnią się od LINQ do SQL (IQueryable)

JAK zbudować warstwę dostępu do danych, warstwę biznesową i warstwę prezentacji za pomocą LINQ na wszystkich warstwach ... i dobry przykład.

Popielniczka
źródło
Pierwsze dwa, które mogę zrobić. Nie chciałbym próbować robić trzeciego jeszcze w sensie „jest to właściwy sposób, aby to zrobić”
Jon Skeet
+1, dopóki tego nie zauważyłeś, nie zdawałem sobie sprawy, że LINQ-to-Objects i LINQ-to-XML były IEnumerable w przeciwieństwie do LINQ-to-SQL jako IQueryable, ale ma to sens. Dzięki!
Precel
2

Jak większość ludzi powiedziała, myślę, że najbardziej źle rozumiane jest założenie, że LINQ jest tylko zamiennikiem T-SQL. Mój menedżer, który uważa się za guru TSQL, nie pozwoliłby nam użyć LINQ w naszym projekcie, a nawet nienawidzi MS za wydanie takiej rzeczy !!!

stackuser1
źródło
2

Transakcje (bez użycia TransactionScope)

Naeem Sarfraz
źródło