Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.
IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

7. diel - LINQ v C# .NET - Revolúcia v dopytovaní

V predchádzajúcom cvičení, Riešené úlohy k 5.-6. lekciu práce s kolekciami v C# .NET, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V dnešnom C# .NET tutoriále sa zameriame na technológiu LINQ, ktorá predstavuje súbor nástrojov na dopytovanie sa na dáta. Jedná sa o veľmi revolučnú technológiu, ktorá prácu s akýmikoľvek dátami zjednodušuje a zovšeobecňuje.

Motivácia

Určite sme všetci doteraz pracovali s rôznymi typmi kolekcií rôznym spôsobom. Inak sme hľadali prvok v poli, inak sme čítali dáta z XML súboru a inak by sme hľadali používateľa v databáze. Predstavte si ale, keby existoval jeden unifikovaný spôsob, akým sa na dáta pýtať. Keby sme mohli tú istú otázku spustiť ako na obyčajnom poli, tak na XML súbore alebo databáze. Asi tušíte, že LINQ nám poskytuje presne taký komfort. Ide o obrovskú abstrakciu, ktorá je vykúpená iba zanedbateľným znížením výkonu a ktorá vyhnala programovanie v C# do nových výšin.

LINQ ako jazyk

LINQ je pomerne sofistikovaná a rozsiahla technológia. Jej názov pochádza z anglického Language INtegrated Query. Ako názov napovedá, jedná sa o dotazovací jazyk, ktorý je integrovaný priamo do syntaxe jazyka C#. Je teda jeho súčasťou a to od C# 3.0 a .NET frameworku 3.5. Od novších verzií beží dokonca na viacerých vláknach, čo zvyšuje efektivitu tejto technológie.

LINQ je veľmi podobný jazyku SQL a je to teda jazyk deklaratívny. Programu oznámime čo hľadáme a už nás veľmi nezaujíma, akým spôsobom pre nás dáta naozaj vyhľadá. Výhodou integrácie LINQ do C# je syntaktická kontrola otázok pri preklade programu.

Urobme si malý príklad, než pôjdeme ďalej. Založte si nový projekt, pôjde o konzolovú aplikáciu s menom LINQ. Vytvoríme si jednoduché pole textových reťazcov.

string[] names = {"David", "Martin", "Daniel", "Peter", "John", "Elisa"};

Teraz si pomocou LINQ dotazu z tohto poľa vyberieme tie položky, ktorých dĺžka je väčšia ako 5 písmen. Do programu zapíšte nasledujúci kód:

var query = from n in names
            where (n.Length > 5)
            select n;

Otázka nápadne pripomína SQL, tí ktorí ho poznajú majú výhodu. Myslím, že SQL nad poľom ste ešte nevolali, že? :) Hneď si otázku podrobne popíšeme, najskôr ale dokončíme náš program a to tým, že si výsledok otázky vypíšeme do konzoly:

// printing the result
foreach (string name in query)
{
    Console.WriteLine(name);
}
Console.ReadKey();

Výstup programu:

Konzolová aplikácia
Martin
Daniel

Ako vyzerá otázka

Vráťme sa k našej otázke, ktorá vyzerala takto:

var query = from n in names
            where (n.Length > 5)
            select n;

Znalci SQL budú určite prekvapení, že je otázka pospiatky. Má to svoje opodstatnenie, ku ktorému dôjdeme.

Najprv určujeme odkiaľ budeme dáta vyberať, slúži na to kľúčové slovo from. Za from nasleduje premenná, ktorá bude vo zvyšku dotazu reprezentovať prvok z kolekcie. Ďalej nasleduje kľúčové slovo in a samotná kolekcia. Je to podobné ako pri cykle foreach. Otázky sa píšu na niekoľko riadkov, aby boli prehľadnejšie. To oceníte najmä u tých zložitejších.

Na opodmienkovanie môžeme uviesť riadok s kľúčovým slovom where, za ním nasleduje podmienka. Podmienky v tomto prípade píšeme úplne rovnako, ako sme to robili doteraz.

Na poslednom riadku nasleduje kľúčové slovo select, pomocou ktorého určíme čo vyberáme. Tu vyberáme celý prvok z kolekcie, teda j. Rovnako tak by sme ale mohli vybrať napríklad len jeho dĺžku j.Length alebo čokoľvek iné.

Kľúčové slovo var

Otázku ukladáme do premennej typu var, s týmto typom sme sa ešte nestretli a vlastne to ani dátový typ nie je. Kľúčové slovo var nám umožňuje prenechať výber dátového typu na kompiléri (rozumajte, že ho za nás priradí C# sám pri preklade). Teoreticky by sme var mohli použiť aj inokedy, napr. takto:

var s = "C# will recognize that this is a string and it will assign the string type to the variable s";
var i = 10;

Kód vyššie C# preloží v podstate na toto:

string s = "C# will recognize that this is a string and it will assign the string type to the variable s";
int i = 10;

Kľúčové slovo var teda umožňuje určiť dátový typ až pri preklade programu a vlastne nás od dátového typu odtieňuje. V bežných programoch by bolo var na ťažkosť, pretože špecifikácia typov má svoj zmysel. Typy teda budeme písať ďalej av žiadnom prípade ich nenahradzujte slovom var, ako sa to niektorí začiatočníci úplne chybne naučia.

Kľúčové slovo var bolo zavedené kvôli LINQ a to z troch dôvodov:

  • Po prvé, dátové typy dotazov sú pomerne zložité a bolo by komplikované ich vždy explicitne špecifikovať.
  • Po druhé, keď zmeníme typ kolekcie, zmení sa aj typ dotazu, čo by vyžadovalo zbytočnú editáciu kódu a znížilo všeobecnosť technológie.
  • Po tretie s LINQom prichádzajú tzv. anonymné typy, pri ktorých sa bez varov nezaobídeme, čoskoro sa k nim dostaneme.

Čo si pamätajte je, že var má svoje miesto hlavne v otázkach av bežnom kóde by sa nemal príliš vyskytovať, aj keď by sa tam teoreticky dalo použiť.

Všeobecne platí poučka, že var môžeme použiť v prípade, že zjednoduší deklaráciu a pritom je stále jasné akého typu premenná je. Ukážme si 4 príklady bez var as var:

int a = 10;
List<Dictionary<string, string>> dictionaries = new List<Dictionary<string, string>>();
IOrderedQueryable<User> fromPrague = from u in db.Users
                                     where u.City == "Prague"
                                     orderby u.Name
                                     select u;
int b = a;

Pomocou var môžeme kód upraviť takto:

var a = 10;
var dictionaries = new List<Dictionary<string, string>>();
var fromPrague = from u in db.Users
             where u.City == "Prague"
             orderby u.Name
             select u;
int b = a;

Pri prvej premennej nám var neprinesie žiadne zjednodušenie. Pri generickom liste generických slovníkov sa jeho použitie naopak oplatí a keďže z pravej strany priradenia aj vidíme akého typu je premenná dictionaries, var je tu aj dobrou voľbou. Rovnako by ale bolo čistejšie napísať na niečo podobné triedu, ukladať kolekcie kolekcií je skôr zlá praktika. Pri LINQ dotaze je typ zložitý a keby sme napr. odmazali orderby, zmenil by sa na IQueryable<User>. Takto nemusíme nad typom premýšľať a ani ho meniť spolu s otázkou. Posledné použitie var je odstrašujúce, vôbec z riadka nepoznáme čo do premennej b ukladáme.

Ďalšou častou chybou je, že si ľudia myslia, že var deklaruje premennú dynamického typu, teda že do nej môžeme uložiť čo chceme. Nie je tomu tak, typ sa napevno určí pri preklade a počas programu ho nemožno meniť. Kód nižšie teda nebude fungovať:

// this code will not work
var variable = "It contains text now";
variable = 10; // Now it contains a number

Program vyššie vytvorí premennú typu string a potom spadne, pretože sa do typu string snažíme uložiť int.

Pod pokrievkou

Ako že to celé funguje? Keď sa pozriete na začiatok vášho zdrojového kódu, uvidíte, že obsahuje nasledujúce using:

using System.Linq;

Ten je prednačítaný pri všetkých typoch projektov. Skúsme ho zakomentovať, v tej chvíli nám Visual Studio podčiarkne v dotaze premennú names.

LINQ funguje pomocou tzv. providerov, tých je niekoľko typov a je aj možné si definovať vlastné. My teraz používame LINQ To Objects, ktorý je implementovaný práve v mennom priestore System.Linq a ktorý rozšíri obyčajné kolekcie ako sú napr. polia a listy o ďalšie metódy navyše. Pod pokrievkou sú teda rozširujúce metódy.

Skúsme si teraz (ešte so zakomentovaným using om) vyvolať ponuku metód na našom poli. Napíšme names. (names a bodku)., aby sme vyvolali zoznam metód na poli:

Obyčajné metódy na poli v C# .NET - Kolekcia a LINQ v C# .NET

Teraz riadok opäť odkomentujme a urobme to isté znova:

Linq metódy na poli v C# .NET - Kolekcia a LINQ v C# .NET

Na obyčajnom poli máme zrazu kvantum nových metód. Keď C# vykonáva LINQ dotaz, volá na pozadí na kolekciu tieto metódy. Tie sú riešené cez lambda výrazy, ktoré sme už stretli v OOP kurze.

Náš dotaz:

var query = from n in names
            where (n.Length > 5)
            select n;

teda C# prežuje a vygeneruje nasledujúci kód:

var query = names.Where(n => n.Length > 5).Select(n => n);

Výstup:

Konzolová aplikácia
Martin
Daniel

Môžete si vyskúšať, že dotaz bude fungovať rovnako. Máme možnosť s LINQ pracovať aj takto, ale pomocou SQL-like zápisu je to oveľa stráviteľnejšie. Mimochodom, práve sme si vysvetlili, prečo je v otázke najprv where a až potom select. Dáta sa musia najprv nájsť metódou Where() az výsledku sa až potom označia čo nás zaujíma metódou Select(). Dôvodom je teda postupnosť metód pod pokrievkou technológie.

Na záver si prezraďme, na čo sa v našom prípade preloží onen záhadný typ var. Výsledný typ dotazu na našom poli je:

System.Linq.Enumerable.WhereArrayIterator<string>

Keďže nemôžeme z hlavy vedieť aký typ LINQ práve vráti (presnejšie povedané by sme od toho mali byť odtienení), bol zavedený typ var, ako už bolo povedané vyššie.

V budúcej lekcii, LINQ provideri, anonymné typy, radenie a zoskupovanie, budeme pokračovať v dopytovaní.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 0x (58.52 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Riešené úlohy k 5.-6. lekciu práce s kolekciami v C# .NET
Všetky články v sekcii
Kolekcia a LINQ v C# .NET
Preskočiť článok
(neodporúčame)
LINQ provideri, anonymné typy, radenie a zoskupovanie
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
1 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity