CodeGym /Kursy /C# SELF /Składnia LINQ: Method Syntax vs Query Syntax

Składnia LINQ: Method Syntax vs Query Syntax

C# SELF
Poziom 31 , Lekcja 1
Dostępny

1. Wprowadzenie

W świecie LINQ są dwie główne "szkoły" pisania zapytań, dwa style, które na pierwszy rzut oka mogą wydawać się zupełnie różne. To Query Syntax (składnia zapytań) i Method Syntax (składnia metod). I jeśli kiedykolwiek myślałeś, że programowanie to tylko logika, to dziś dodamy trochę sztuki, bo wybór składni często przypomina wybór między pędzlem a ołówkiem: oba narzędzia rysują, ale jedno może lepiej oddać kolor, a drugie — kontur.

Po co nam dwie składnie? Dobre pytanie! Wyobraź sobie, że chcesz zamówić kawę. Możesz powiedzieć: "Czy mogę prosić filiżankę espresso z mlekiem i jedną łyżeczką cukru?". A możesz napisać na kartce: "Espresso. Mleko. 1 cukier". Obie opcje są zrozumiałe, ale jedna jest bardziej rozmowna, druga — bardziej zwięzła.

Tak samo jest z LINQ. Jedna składnia została stworzona, by być maksymalnie podobną do języka baz danych SQL, a druga — by być bardziej "C#-owa" i elastyczna. Ostatecznie kompilator C# zamienia oba style na to samo: wywołania metod. Więc wybór często sprowadza się do czytelności i osobistych preferencji.

Zobaczmy oba style.

2. Method Syntax

To wariant, w którym wywołujesz metody rozszerzające LINQ jedna po drugiej przez kropkę. Takie podejście jest szczególnie popularne wśród .NET-deweloperów, bo łatwo dodawać nowe operacje, wynik zawsze jest IEnumerable<T>, i wygodnie się pisze bezpośrednio w kodzie.

Przykład: Filtrowanie i sortowanie produktów


var filteredProducts = products
    .Where(p => p.Price < 1000)          // Filtrowanie po cenie
    .OrderBy(p => p.Name)                // Sortowanie po nazwie
    .ToList();                           // Konwersja do List<Product>

Where, OrderBy i ToList — to metody rozszerzające LINQ, każda zwraca nowy zbiór danych, który można dalej przetwarzać.

Schemat


graph LR
A[products] --> B[Where]
B --> C[OrderBy]
C --> D[ToList]
Kolejność wywołań w Method Syntax

Dlaczego Method Syntax jest fajny

  • Bardzo elastyczny: łatwo budować złożone łańcuchy wielu operacji.
  • Wszystko to zwykłe metody C#, IDE pomaga z podpowiedziami.
  • Pozwala robić prawie wszystko, co jest w LINQ (a nawet więcej).

Kolejny przykład: wybór imion wszystkich użytkowników powyżej 18 lat

Załóżmy, że mamy klasę User:


public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Teraz wybierzemy imiona dorosłych użytkowników:


List<User> users = ... // gdzieś zadeklarowane

var adultNames = users
    .Where(u => u.Age >= 18)
    .Select(u => u.Name)
    .ToList();

3. Query Syntax (składnia podobna do SQL)

Ta składnia została specjalnie wymyślona, żeby deweloperzy C# czuli się jak w domu, jeśli wcześniej pracowali z SQL. Przypomina zapytania do bazy danych i zaczyna się od słowa kluczowego from.

Przykład: ten sam filtr i sortowanie


var filteredProducts = 
    from p in products
    where p.Price < 1000
    orderby p.Name
    select p;

Tutaj wszystko czyta się jak klasyczne zapytanie: "z kolekcji products weź p, gdzie p.Price < 1000, posortuj po p.Name, wybierz p".

Schemat


flowchart TD
    A[products] -->|from p in products| B[where p.Price < 1000]
    B --> C[orderby p.Name]
    C --> D[select p]
Etapy zapytania w Query Syntax

Dlaczego Query Syntax jest fajny

  • Przypomina SQL, więc jest bardziej zrozumiały dla tych, którzy już pracowali z bazami danych.
  • Bardziej czytelny dla długich zapytań z wieloma warunkami, grupowaniem, łączeniem (join).

Kolejny przykład: wybór imion dorosłych użytkowników


var adultNames = 
    from u in users
    where u.Age >= 18
    select u.Name;

Zwróć uwagę: Tutaj od razu po select możesz wybrać nie cały obiekt, a konkretne pole — na przykład tylko imię.

4. Porównanie: Method Syntax vs Query Syntax

Method Syntax Query Syntax
Składnia
users.Where(...).Select(...)
from u in users where ... select ...
Przypomina Zwykłe metody/łańcuchy SQL
Gdzie używać Zawsze, do dowolnych operacji Nie wszystkie operacje dostępne (np.
Sum
,
Count
tylko w Method Syntax)
Czytelność Dobre dla łańcuchów Wygodniejsze dla grupowania, łączenia
Co zwraca Zwykle
IEnumerable<T>
Zwykle
IEnumerable<T>
, ale czasem trzeba
.ToList()
dla listy

Ciekawostka z życia

Większość przykładów w oficjalnej dokumentacji Microsoft do LINQ jest podana od razu w obu stylach. Ale w kodzie produkcyjnym coraz częściej spotyka się Method Syntax — jest wygodniejszy przy integracji z metodami rozszerzającymi (Where, Select, OrderBy i tak dalej).

Mieszać czy nie mieszać? Jaki styl wybrać

Można swobodnie łączyć oba style w jednym projekcie (a nawet w jednym zapytaniu — ale wygląda to dziwnie). Najważniejsze — nie robić z kodu sałatki. Zwykle wybiera się jeden styl na cały moduł lub projekt, żeby kod był łatwiejszy do czytania.

Method Syntax świetnie nadaje się do sekwencyjnych przekształceń i używania wszystkich metod LINQ, które są tylko jako metody (Sum, Count, Any i kilka innych).

Query Syntax jest bardzo wygodny do zadań z join, group by albo złożonymi wielopoziomowymi warunkami — tam wygrywa czytelnością.

5. Przekształcanie między stylami: to samo, ale inaczej

LINQ w C# zamienia każde zapytanie podobne do SQL (Query Syntax) na łańcuch wywołań metod (Method Syntax). Czyli, cokolwiek napiszesz, C# i tak sprowadzi to do metod rozszerzających przy kompilacji.

Przykład 1 — filtrowanie:

Query Syntax:


var adults = from u in users
             where u.Age >= 18
             select u;

Method Syntax (odpowiednik):


var adults = users.Where(u => u.Age >= 18);

Przykład 2 — wybieranie pól (Select):

Query Syntax:


var names = from u in users
            select u.Name;

Method Syntax:


var names = users.Select(u => u.Name);

7. Grupowanie i łączenie (join, group by)

Tworzenie nowych obiektów

Dodajmy do naszej aplikacji edukacyjnej możliwość wyświetlania listy użytkowników pogrupowanych według wieku. Tutaj różnica w składni staje się szczególnie widoczna.

Query Syntax (grupowanie):


var usersByAge = 
    from u in users
    group u by u.Age into ageGroup
    select new { Age = ageGroup.Key, Users = ageGroup.ToList() };

Grupujemy użytkowników według wieku (group u by u.Age). Po into pojawia się zmienna ageGroup — to już sama grupa.

Method Syntax (odpowiednik):


var usersByAge = users
    .GroupBy(u => u.Age)
    .Select(ageGroup => new { Age = ageGroup.Key, Users = ageGroup.ToList() });

Jeszcze trudniej: łączenie (join)

Załóżmy, że mamy listę zamówień (orders) i listę użytkowników (users). Chcemy uzyskać imiona użytkowników i sumę ich zamówień.

Query Syntax:


var userOrders =
    from user in users
    join order in orders on user.Id equals order.UserId
    select new { user.Name, order.Amount };

Method Syntax:


var userOrders = users.Join(
    orders,
    user => user.Id,
    order => order.UserId,
    (user, order) => new { user.Name, order.Amount }
);

8. Częste błędy, pułapki i lifehacki

Jedno z najczęstszych nieporozumień: jeśli nie dodasz .ToList(), wynik — to nie lista, tylko "leniwe zapytanie" (lazy query), które wykona się dopiero przy pierwszym przejściu po kolekcji. To wygodne, ale może prowadzić do nieoczekiwanych rezultatów, jeśli oryginalna kolekcja zmieni się po napisaniu zapytania. Więcej o "leniwej ewaluacji" pogadamy osobno (po poznaniu metod LINQ).

Wielu początkujących myli się, że można użyć wszystkich metod LINQ w Query Syntax. Na przykład nie da się po prostu napisać select sum(u.Age), trzeba przejść do Method Syntax (users.Sum(u => u.Age)).

2
Zadanie
C# SELF, poziom 31, lekcja 1
Niedostępne
Zastosowanie Query Syntax do filtrowania i sortowania
Zastosowanie Query Syntax do filtrowania i sortowania
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION