Wśród feature‘ów wprowadzonych w wersji 3.5 frameworka .NET jest między innymi LINQ (Language INtegrated Query). Mechanizm ten umożliwia – w dużym skrócie rzecz jasna – konstruowanie zapytań odnoszących się do kolekcji obiektów (w zasadzie dowolnego rodzaju) przy pomocy operatorów znanych z relacyjnych baz danych, jak SELECT
czy WHERE
. Ponadto w .NET 3.5 język C# został też odpowiednio rozszerzony, aby zapytania ta składniowo mogły przypominać kwerendy podobne do tych występujących w różnych odmianach języka SQL.
“A po co to komu?”, można zapytać od razu i nie ukrywam, że moja reakcja na LINQ była podobna. W końcu kto by chciał zaśmiecać taki ładny język jak C# zupełnie nieprzydatnym nikomu SQL-em? ;] Poza tym mówimy tutaj o czymś trochę z innej bajki, bowiem języki zapytań różnią się od języków programowania tym, że są deklaratywne: pisanie w nich polega na określeniu, co chcemy otrzymać – nie zaś tego, co po kolei program ma robić. (Jak nietrudno się domyślić, ogranicza to trochę stosowalność takich języków). Czemu więc chce się te dwie rzeczy połączyć?…
Odpowiedź jest jak zwykle dość prosta: dla wygody. Za pomocą LINQ nie zrobi się niczego nowego, ale pewne operacje można wykonywać prościej. Czasami można sobie oszczędzić dodatkowych pętli i zmiennych lokalnych – jak chociażby w poniższym przykładzie, w którym chcemy pobrać wszystkie wartości zaznaczone na liście z polami wyboru (check box list) i coś z nimi zrobić:
Można się oczywiście spierać, która wersja jest czytelniejsza i którą jest łatwiej/szybciej napisać. To jednak jest w dużym stopniu kwestią subiektywną. Jak dla mnie możliwość uniknięcia kolejnej pętli, która udaje, że coś robi (a tak naprawdę tylko przerzuca dane z jednego miejsca w inne) jest całkowicie zadowalająca.
Przy bardziej skomplikowanych przypadkach miałbym aczkolwiek dużo większe możliwości. Jest oczywiście możliwe pisanie błyskotliwych kwerend przemiatających po cztery pojemniki naraz i używających takich operatorów jak group
czy orderby
, by zrobić w trzech linijkach zapytania to, co inaczej wymagałoby 20 wierszy kodu. Sęk w tym, że prawdopodobnie odczytanie znaczenia tych 20 wierszy byłoby wówczas znacząco łatwiejsze ;P
Warto się także zastanowić która wersja jest wydajniejsza i czy LINQ nie robi jakiś (nie zawsze) nie potrzebnych rzeczy. Choć sam nie wiem jak sprawa przedstawia się w LINQ, to z chęcią poznałbym zdanie kogoś zorientowanego.
Nie podoba mi się ta inwersja nawet pseudozapytania SQL. MS zawsze musi zrobić coś po swojemu. Ale nie powiem, przypomina mi to pewne konstrukcje w pythonie, a dokłaniej:
do_something([int(item.value) for item in objects_list if item.selected])
Czy jest bardziej czytelne? Kwestia przyzwyczajenia do języka, przynajmniej Python wykorzystuje standardowe słowa kluczowe, a nie dodaje nowe.
@Suvroc:
LINQ to tak naprawdę zbiór metod rozszerzających, które można sobie bezproblemowo podejrzeć reflectorem. Nie ma tam nic nadzwyczajnego – po prostu dla każdego elementu wykonuje się ileś tam przekazanych instrukcji. Jedyna różnica między LINQ a “normalnym” programowaniem jest taka, że wykonanie zapytania w LINQ jest odłożone w czasie aż do momentu jego faktycznego wywołania. Sama instrukcja:
var query = from element in list where element.Value > 3 select element;
nie chodzi po żadnych listach,nie wykonuje żadnych pętli. Dopiero w momencie przejechania się po niej pętlą foreach lub wywołania którejś z metod z rodziny To…(), jak ToList() czy ToArray() z listy pobierane są elementy spełniające dane kryteria. A do tej pory możesz owo zapytanie komplikować, nie zwiększając jednocześnie liczby iteracji po liście:
query = from e in query where e < 10 select e;
@zwierzak:
Kolejność elementów musiała zostać zmieniona względem standardowego sql ze względu na intellisense. Zaczynając instrukcję od:
select … <- jaka podpowiedź ma się tu pojawić?
Natomiast definiując “from” możemy oczekiwać pełnego wsparcia ze strony IDE.
A składnia… na początku może wydawać się trochę zamotana (szczególnie wersja wykorzystująca bezpośrednio metody rozszerzające a nie nowe słowa kluczowe C#), ale po kilku chwilach pracy z LINQ i zrozumieniu jego działania o wiele łatwie jest czytać kod LINQ niż pozagnieżdżane pętle robiące nie wiadomo co.
Należy pamiętać też o tym, że LINQ powstał głównie z myślą o wspomaganiu dostępu do baz danych. Tak naprawdę jest to dosyć prosty ORM, gdzie możemy tworzyć model bazy danych, który mapuje struktury bazy na klasy. Dzięki temu unikamy np. używania zapytań SQL w postaci stringów i wykorzystujemy LINQ, którego poprawność jest przecież weryfikowana już przez kompilator, a nie dopiero silnik bazy danych.
Ja wolę jeszcze inną wersję:
DoSomething (checkBoxList.Items
.Where(i=>i.Selected)
.Select(i=>Convert.ToInt32(i.Value));
@zwierzak: MS odwrócił kolejność, żeby mógł działać Intellisense i to był jedyny powód.
@Hornet: LINQ to cecha języka (moim zdaniem jedna z genialniejszych w C#). Nie zgodzę się z Tobą przy sprowadzaniu LINQ do konkretnej implementacji bazodanowej – Linq2SQL. Wg mnie LINQ, to nowe podejście do źródeł danych, jakąkolwiek postać one przyjmują (obiekty, DB, XML, itp.).
LINQ to niestety spory niewypał :( Buduje w programiście fałszywą ułudę wydajności (mniej linijek kodu). W praktyce jest dużo wolniejszy, niż własnoręcznie wklepany kod, bo przy bardziej rozbudowanych operacjach tworzy masę obiektów tymczasowych, i przerzuca dane z jednej kupki na drugą, nie “martwiąc” się o żadne optymalizacje. Generalnie trzeba się przy nim pilnować, bo może fatalnie wpłynąć na wydajność kodu.
jakubin: Nie ograniczam LINQ do LinqToSQL, chciałem jedynie podkreślić zalety LINQ w tym konkretnym zastosowaniu.
Trzeba również wspomnieć, że LINQ nie będzie dalej wspierany przez Microsoft, który to postanowił skupić się na rozwijaniu Entity Frameworka.
@Hornet – najpierw tłumaczysz że chodziło ci o LINQ To SQL, a potem znowu piszesz o tym, że MS nie wspiera LINQ…
MS przestał rozwijać LinqToSql, a nie Linq !!! Entity Framework także korzysta z Linq, ale implementacja to LinqToEntities.
Fakt, przepraszam, miało być LinqToSQL.
@Ciekawski – jak jesteś takim zwolennikiem szybkiego kodu klepanego ręcznie to się na asmblera przesiądź. a czy coś jest niewypałem to ocenimy jak wejdzie coś nowego lub LINQ się rozwinie