Kezdőlap > .NET, C#, Linq > Bevezetés a LINQ világába–(3. rész) Linq To Objects

Bevezetés a LINQ világába–(3. rész) Linq To Objects

2011. június 9. csütörtök Hozzászólás Go to comments

Az alábbi fejezetek a “Bevezetés a LINQ világába” c. irományomból valóak. Ez egy saját kis jegyzet, reményeim szerint hasznát tudjátok venni. Amiben viszont én kérném a segítségeteket az az, hogy az írást javítsátok. Ha fogalmazási, stilisztikai vagy esetleg tartalmi hibát vélnétek felfedezni kérlek írjátok meg a kommentek között.
Segítségetek előre is köszönöm.

Linq To Objects

A következő fejezetben a Linq To Object-tel fogunk megismerkedni. A nyelvbe ágyazott lekérdezés segítségével egyszerűen tudunk objektumokból, gyűjteményekből lekérdezni számunkra szükséges információkat, anélkül, hogy extra erőt fordítanánk ezen adatok kinyerésére (speciális metódusok írására stb.). Persze van egy minimális overheadje, de cserébe az egyszerűséget és az átláthatóságot kapjuk tőle. Sok vita kering az interneten arról, hogy használjuk vagy ne használjuk a LINQ-t, mert tény, hogy lassúbb tud lenni (nem mindig), mintha mi írnánk meg például egy speciális sorba rendezést, de cserébe az egyszerűséget kapjuk. Lehet mérlegelni, hogy mikor melyiket használjuk. Én azt vallom, hogy kis- és közepes alkalmazásoknál célszerű a Linq használata, hisz nem vesztünk vele akkor teljesítményt, viszont olyan Enterprise-alkalmazásoknál, ahol a válaszidő 0,001 másodperce is lényeges, célszerűbb saját Enterprise-megoldás után nézni. Talán nem a legjobb hasonlat, de ez olyan, mint a managelt―nem managelt világ összehasonlítása. Tudjuk, hogy (nagyrészt) az unmanaged kód gyorsabb, de viszonylag nehéz benne dolgozni, míg a managed világban minden a kezünk alá van adva, és segíti a munkánkat, hogy hatékonyabban és gyorsabban tudjunk dolgozni.

Linq To Object alapvető metódusai

A következő demoban egy gyűjtemény elemein fogjuk megismerni a Linq To Objects-et.

1. Készítsünk egy új Console Application-t, és legyen a neve, mondjuk, ConsoleLinq.

2. Adjunk hozzá egy új osztályt, amelynek a neve Person lesz.

(Solution Explorer -> Add -> Class)

3. A Person osztály az alábbi elemeket fogja tartalmazni

public class Person

{

    public int Id { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    public string City { get; set; }

    public string Job { get; set; }

}

4. Térjünk vissza a Program.cs -hez és Main-be készítsünk egy Listát, amely Person objektumokat tartalmaz.

List<Person> persons = new List<Person>();

5. Ezt követően adjunk ehhez a listához 4 elemet.

Person p1 = new Person

{ Id = 1, Name = "Attila", Age = 25, City = "Budapest", Job = "Devloper" };

persons.Add(p1);

 

Person p2 = new Person

{ Id = 2, Name = "Gergő", Age = 26, City = "Miskolc", Job = "IT" };

persons.Add(p2);

 

Person p3 = new Person

{ Id = 3, Name = "Szabolcs",  Age = 28, City = "Üröm", Job = "Manager" };

persons.Add(p3);

 

Person p4 = new Person

{ Id = 4, Name = "David", Age = 26, City = "Budapest", Job = "Trainer" };

persons.Add(p4);

Látható, hogy az objektumok adatainak megadásánál a C# 3.0-nál bevezetett object initializer-t használtuk. (Ezt a gyűjtemény feltöltésénél is megtehettük volna.)

6. Most, hogy már megvagyunk a lista feltöltésével, itt az ideje lekérdezni a benne található elemeket. A lekérdezést értelemszerűen a select utasítással tudjuk megtenni. Mint tudjuk a Query Expressiont a fordító bővítő metódusos kifejezésé alakítja.

Ezért a lekérdezéseknél, mindkét alakját megnézzük a lekérdezésnek. Igazából teljesen mindegy, hogy melyiket használjuk, vegyük azt, amelyik jólesik. Összetettebb lekérdezéseknél talán a Query Expression-ös módszer átláthatóbb, mint a bővítő metódusos, de ez is csak megszokás kérdése.

7. Első lépésként kérdezzük le a gyűjtemény összes elemét.

var res = from c in persons

          select c;

Ne feledjük a két kifejezés ekvivalens!

var res = persons.Select(c => c);

8. Kiíratni pl. a következőképpen lehet az eredményt.

foreach (var item in res)

{

    Console.WriteLine(item.Name + ": " + item.Age);

}

Helytakarékosság végett csak ennél a példánál mutatom be az eredmények kiíratását. A többinél ugyanezzel az analógiával kell kiíratni az eredményeket. Csak figyeljünk oda, hogy amikor lekérdeztünk, az mivel tér vissza!

9. A lista összes elemét le tudjuk kérdezni; de mi van akkor, ha minket a Person listából csak a felhasználók állásai érdekelnek? Tehát a többi felesleges információ nem érdekes. Természetesen ezt is le tudjuk kérdezni az alábbi módon:

var res = from c in persons

          select c.Job;

var res = persons.Select(c => c.Job);

10. Egy elemet egyszerű lekérdezni, de mi van akkor, ha minket mondjuk a Personok nevei és életkora érdekel? Ilyenkor felmerül az ötlet, hogy például vesszővel válasszuk el az elemeket, és soroljuk fel. Hát ez az, ami NEM így működik. Ilyenkor szükségünk lesz egy átmeneti osztályra.

Hozzunk létre egy átmeneti TempPerson osztályt.

public class TempPerson

{

    public string Name { get; set; }

    public int Age { get; set; }

}

11. Kérdezzük le a Person Listában található emberek nevét és korát:

var res = from c in persons

          select new TempPerson

          {

              Name = c.Name,

              Age = c.Age

          };

var res = persons.Select(c => new TempPerson { Name = c.Name, Age = c.Age });

12. Ez szép, de mindig egy-egy átmeneti osztályt létrehozni egyetlen lekérdezés kedvéért elég macerás. Ezért létrehozták a C# 3.0-ban az Anonymus-típusokat ― ezzel is egyszerűsítve a Linq-t használók dolgát. Kérdezzük ugyanúgy le a Personok neveit és életkorait, csak immár Anonymus-típust felhasználva.

var res = from c in persons

          select new

          {

              Name = c.Name,

              Age = c.Age

          };

var res = persons.Select(c => new { Name = c.Name, Age = c.Age });

imageFigyeljük meg, hogy a new kulcsszó után nem áll osztálynév. Így ő egy Anonymus-típus lesz. Óvatosan bánjunk az Anonymus-típussal, őket se használjuk ész nélkül, s ugyanígy a var-t se!

 

13. Lekérdezni már tudunk, de a lekérdezés mit se érne, ha nem tudnánk szűkíteni valamilyen módon az eredményhalmazt. Erre lesz tökéletes társ a Where kulcsszó.

Kérdezzük le azokat a Personokat, akik budapestiek.

var res = from c in persons

          where c.City == "Budapest"

          select c;

var res = persons.Where(c => c.City == "Budapest");

14. Ha már tudunk szűrni, akkor itt az ideje sorba rendezni az elemeket mind növekvő, mind csökkenő sorrendben. Rendezzük név szerint növekvő sorrendbe a felhasználókat.

var res = from c in persons

          orderby c.Name

          select c;

var res = persons.OrderByDescending(c => c.Name).Select(c => c);

15. Ugyan ez a lekérdezés csökkenő sorrendben a következőképpen néz ki:

var res = from c in persons

          orderby c.Name descending

          select c;

var res = persons.OrderByDescending(c => c.Name).Select(c => c);

imageFigyeljük meg, hogy Query Expression-nél csak egy descending kulcsszavat raktunk az orderby után, míg a bővítő metódusánál ez már nem az OrderBy metódust hívta meg egy külön paraméterrel, hanem az OrderByDescending metódust.

16. Gyakori szkenárió az is, hogy a sorba rendezés után további elemeket is szeretnénk sorba rendezni. Ezt a ThenBy, ThenByDescending bővítő metódussal érhetjük el. Query Expression-nél egyszerűen csak egy vessző után felsoroljuk a következő elemeket, amiket rendezni szeretnénk.

var res = from c in persons

          orderby c.Name, c.Age

          select c;

var res = persons.OrderBy(c => c.Name).ThenBy(c => c.Age).Select(c => c);

17. Hasznos, bár kevésbé gyakori eset, amikor a lekérdezett elemek sorrendjét meg szeretnénk fordítani. Azaz, hogy az eddig az eredmény listában lévő elem az első elem legyen. Erre lesz hasznos társ a Reveres bővítő metódus. Ez a metódus azért is különleges, mert nincs Query Expression-ös alakja. Azaz csak úgy tudjuk Query Expression esetében meghívni, ha bővítő metódusként használjuk az alábbi módon (ilyenkor a kifejezést zárójelbe rakjuk):

var res = (from c in persons

           orderby c.Age

           select c).Reverse();

var res = persons.OrderBy(c => c.Age).Select(c => c).Reverse();

Kategóriák:.NET, C#, Linq Címke: , , , ,
  1. 2011. június 9. csütörtök - 11:06

    14. pontban a kiterjesztett metódusos lekérdezés kódja hibás.

    17. Pontban egy elgépelés: “Reveres”

  2. 2011. június 9. csütörtök - 11:21

    Ah rosszat copyztam 🙂 Kösz.

  3. 2011. június 9. csütörtök - 12:08

    ” Mint tudjuk a Query Expressiont a fordító bővítő metódusos kifejezésé alakítja.”

    Tudjuk? Amúgy mi az a Query Expression?

    “Mint tudjuk a Query Expressiont a fordító bővítő metódusos kifejezésé alakítja.”

    Tudjuk?

    “Ezért a lekérdezéseknél, mindkét alakját megnézzük a lekérdezésnek.”
    Nincs jelölve hogy melyik melyik. Most akkor melyik a query expression?

    Ezek a kani nagy információs gombok félelmetesek. Remélem a jegyzetben kisebbek lesznek valamivel.

    ” Query Expression-nél egyszerűen csak egy vessző után felsoroljuk a következő elemeket, amiket rendezni szeretnénk.”
    Innentől legalább egyértelmű hogy melyik a query expression.

    Nem tudom hogy ezek a fogalmak az előző két bejegyzésben definiálva lettek-e, ha igen akkor a jegyzetben egyértelmű lesz hogy melyik micsoda.

    Esetleg szerintem még beleférne egy rövid magyarázat hogy a lekérdezés szintaktikája miért ‘fejre állított sql lekérdezés’-re hasonlít.

    Amúgy szerintem jó. Tömör, lényegre törő.

    Morzel

  4. 2011. június 9. csütörtök - 12:59

    Kösz, javítom. Igazad van. Nem definiáltam.

  5. 2011. június 9. csütörtök - 13:43

    Egy sör lesz és 100 mineral :))

    Morzel

  6. 2011. június 9. csütörtök - 13:45

    50 minerál és áll az alku 🙂

    • 2011. június 9. csütörtök - 14:19

      Ok. Szerencsére a sörre nem licitáltál.

      Morzel

  7. reiteristvan
    2011. június 10. péntek - 09:39

    Ez:

    var res = from c in persons

    where c.City == “Budapest”

    select c;

    Nem egyenértékű ezzel:

    var res = persons.Where(c => c.City == “Budapest”).Select(c => c);

    Ugyanis az utóbbi esetben a végén a Select gyakorlatilag semmit nem csinál, viszont egy plusz metódushívásba kerül, mivel a fordító mindenképp legenerálja a hozzá tartozó metódust (pont ezért van, hogy a Where kvázi subquery önmagában is visszaadja a kért eredményhalmazt, nem kell hozzá select ha a végeredményen nem akarsz alakítani).
    A fölső változatban hiába van ott a select a kifejezés végén, az csak a szintaxis miatt kell, nem csinál vele semmit a fordító.

    Nézd meg ildasm-mal, a második lekérdezésnél egy második Func is megjelenik.

  1. No trackbacks yet.

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: