cuprins expresii lambda (lambda expressions). arbori de ...iasimin/csharp/c11_linq.pdf · linq to...

22
LINQ - Language Integrated Query 05.01.2014 Ioan Asiminoaei Cuprins Expresii lambda (Lambda expressions). Arbori de expresii (Expression trees). Cuvantul cheie var obiecte si initializarea colectiilor. tipuri anonime, new – forma noua. Metode extinse (Extension methods). Metode partiale (Partial methods). Query expressions.

Upload: voliem

Post on 10-Apr-2018

231 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Cuprins

Expresii lambda (Lambda expressions).

Arbori de expresii (Expression trees).

Cuvantul cheie var obiecte si initializarea colectiilor.

tipuri anonime, new – forma noua.

Metode extinse (Extension methods).

Metode partiale (Partial methods).

Query expressions.

Page 2: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

LINQ - Language Integrated Query = Cereri asupra datelor

LINQ este o tehnologie Microsoft ce furnizeaza un mecanism la nivel de limbaj pentru a executa cereri

de date de orice tip.

Cateva exemple :

Exemplul 1

using System; using System.Linq; string[] greetings = {"hello world", "hello LINQ", "hello Apress"};

var items = from s in greetings where s.EndsWith("LINQ") select s;

foreach (var item in items) Console.WriteLine(item);

Exemplul 2

Se parseaza continutul unui fisier XML ce are urmatoarea structura:

<books> <book> … </book>

<book> … </book> <book> … </book> … <book> … </book>

</books>

Codul este urmatorul.

using System; using System.Linq; using System.Xml.Linq; XElement books = XElement.Parse( @"<books> <book> <title>Pro LINQ: Language Integrated Query in C# 2008</title> <author>Joe Rattz</author> </book> <book> <title>Pro WF: Windows Workflow in .NET 3.0</title> <author>Bruce Bukovics</author> </book> <book> <title>Pro C# 2005 and the .NET 2.0 Platform, Third Edition</title> <author>Andrew Troelsen</author> </book> </books>");

Page 3: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

var titles = from book in books.Elements("book") where (string) book.Element("author") == "Joe Rattz" select book.Element("title");

foreach(var title in titles)

Console.WriteLine(title.Value);

Exemplul 3

string[] numbers = { "0042", "010", "9", "27" }; int[] nums = numbers.Select(s => Int32.Parse(s)).ToArray(); foreach(int num in nums) Console.WriteLine(num);

Exemplul 4

public class Employee {

public int id; public string firstName; public string lastName; public static ArrayList GetEmployees() { ArrayList al = new ArrayList(); al.Add(new Employee { id = 1, firstName = "Joe", lastName = "Rattz"} ); al.Add(new Employee { id = 2, firstName = "William", lastName = "Gates"} ); al.Add(new Employee { id = 3, firstName = "Anders", lastName = "Hejlsberg"} ); return(al); }

}

public class Contact {

public int Id; public string Name; public static void PublishContacts(Contact[] contacts) { foreach(Contact c in contacts) Console.WriteLine("Contact Id: {0} Contact: {1}", c.Id, c.Name); }

}

...

Page 4: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

ArrayList alEmployees = Employee.GetEmployees(); Contact[] contacts = alEmployees.Cast<Employee>()

.Select(e => new Contact {

Id = e.id, Name = string.Format("{0} {1}", e.firstName, e.lastName)

}).ToArray<Contact>(); PublishContacts(contacts);

Rezultatul este:

Contact Id: 1 Contact: Joe Rattz

Contact Id: 2 Contact: William Gates

Contact Id: 3 Contact: Anders Hejlsberg

LINQ

LINQ este o tehnologie Microsoft ce furnizeaza un mecanism la nivel de limbaj pentru a executa cereri

de date de orice tip. Aceste tipuri includ tablouri si colectii in memorie, baze de date, documente

XML, etc. Printre altele LINQ poate face conversii, poate sorta, poate obtine o submultime a unei

multimi date, etc.

// conversie array de string-uri in array de int. Aceasta este o cerere. string[] numbers = { "0042", "010", "9", "27" }; int[] nums = numbers.Select(s => Int32.Parse(s)).ToArray(); // se face si sortarea int[] nums = numbers.Select(s => Int32.Parse(s)).OrderBy(s => s).ToArray();

In LINQ, multimea de obiecte returnata se numeste sir. Majoritatea sirurilor din LINQ sunt de tip

IEnumerable<T> sau dintr-un tip derivat din IEnumerable<T> , unde T este tipul de data al obiectelor memorate in sir (int, string, double, etc.).

La runtime cand se cer elemente din colectie, are loc un proces de construire a elementelor

submultimii. In acest moment pot aparea exceptii.

Ex. string[] strings = { "Iasi", "Pascani", null, "Harlau" }; Console.WriteLine("Inainte ca Where() sa fie apelat."); // definim multimea ieStrings IEnumerable<string> ieStrings = strings.Where(s => s.Length == 3); Console.WriteLine("Duap ce Where() este apelat."); // Cand se va executa foreach va aparea o exceptie pentru ca // al 3-lea element al sirului are valoarea null, vedeti Where... // Daca nu se extrag elemente din ieStrings nu va aparea exceptia foreach(string s in ieStrings) {

Console.WriteLine("Procesat " + s); }

Page 5: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Componente :

1. LINQ to Objects – este numele dat API-ului IEnumerable<T> pentru operatorii de cereri

standard. Putem face cereri asupra tablourilor sau colectiilor din memorie. Operatorii standard

sunt metode statice ale clasei System.Linq.Enumerable.

2. LINQ to XML – API dedicat sa lucreze cu XML. Trebuie sa adaugam o referinta la proiect

System.Xml.Linq.dll si apoi using System.Xml.Linq;

3. LINQ to DataSet – API Linq pentru DataSet-uri.

4. LINQ to SQL – API IQuerable<T> ce permite Linq sa lucreze cu SQL Server si nu numai.

Trebuie referinta la System.Data.Linq.dll si apoi using System.data.Linq ;

5. LINQ to Entities – alternativa la Linq folosit pentru interfata cu bazele de date. Se decupleaza

entitatea model obiect de baza de date (fizic) prin crearea unei logici intre cele doua niveluri.

Trasaturi noi in .NET • Expresii lambda (Lambda expressions) ;

• Arbori de expresii (Expression trees);

• Cuvantul cheie var, obiecte si initializarea colectiilor, tipuri anonime, new – forma noua;

• Metode extinse (Extension methods);

• Metode partiale (Partial methods);

• Expresii cerere (Query expressions).

Metode partiale

Scriem prototipul intr-un loc si codul in alt loc. Daca nu scriem codul atunci compilatorul nu emite cod

pentru acea metoda, iar apelul metodei nu are efect (nu se genereaza exceptie).

Putem sa le folosim cand dezvoltam un tip si nu implementam toate metodele. Le vom implementa

mai tarziu sau altcineva va implementa acele metode dar nu va avea acces la implementarea metodelor

facuta de noi.

Reguli pentru metodele partiale

� Metodele partiale trebuiesc sa fie definite si implementate numai in clase partiale.

� Metodele partiale trebuie sa specifice modificatorul partial.

� Metodele partiale sunt private dar nu trebuie sa specifice modificatorul private, in caz contrar

eroare la compilare.

� Metodele partiale trebuie sa returneze void.

� Metodele partiale pot fi neimplementate.

� Metodele partiale pot fi statice.

� Metodele partiale pot avea argumente.

Page 6: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Exemplu namespace PM { partial class A { partial void MetodaPartiala(string s); } // Ceea ce urmeaza trebuie sa fie in alt fisier partial class A { // Daca comentam aceasta linie programul tot se va compila partial void MetodaPartiala(String s) { Console.WriteLine("MetodaPartiala apelata cu: {0}", s); } } }

Ex.

public partial class PartialA {

partial void Start(int count); partial void End(int count); public PartialA() {

int count = 0; Start(++count); Console.WriteLine("In ctor PartialA."); End(++count); Console.WriteLine("count = " + count);

} }

Obs. count ramane nemodificat (Verificati!). Metodele partiale Start si End nu sunt implementate.

Metode extinse O metoda extinsa este o metoda statica a unei clase statice pe care o putem apela ca si cum ar fi o

metoda de instanta a unei alte clase.

Sunt de folos cand dorim sa extindem o clasa ce e declarata sealed sau nu avem codul clasei.

Declararea primului parametru al unei metode cu cuvantul cheie this face ca metoda

sa fie extinsa. Metoda trebuie sa fie statica, iar clasa in care se declara trebuie sa fie

statica.

Se extinde clasa data de primul parametru al metodei (in exemplul de mai jos String).

public static class StringConversions {

public static double ToDouble(this string s) {

return Double.Parse(s); } public static bool ToBool(this string s) {

return Boolean.Parse(s);

Page 7: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

} }

...

// Se apeleaza ca in exemplul de mai jos string str = “123.45”; Console.WriteLine(str.ToDouble());

Observatie

Metodele de instanta ale obiectului au prioritate fata de metodele extinse.

Expresii lambda

Scopul lor este de a furniza un algoritm ca argument al unei metode.

Delegates anonimi. Vezi .NET 2.0 si ca exemplu clasa Ex4 pentru acest curs.

In C# lambda expresia arata astfel :

(param1, param2, …paramN) => {

statement1; statement2; … statementP; return(lambda_expression_return_type);

}

Se citeste astfel: pentru valorile de intrare date prin parametrii param1, param2, ..., paramN se

va executa codul statement1 ; statement2 ;...statementP iar valoarea returnata este cea

data de return (aici se stabileste si tipul valorii returnate).

In Ex4 tipul valorii de retur (ce este bool) este stabilita de delagate-ul definit in clasa

DelegateAnonim :

public delegate bool IntFilter(int i);

Exemple:

x=> x.Length // tip returnat int x => "Procesat " + x // tip returnat string (x trebuie sa fie string) x => x.Length > 0 // tip returnat bool (x, y) => x == y // tip returnat bool

Observatie:

Expresia lambda trebuie sa accepte in intrare tipurile specificate de delegate si sa returneze acelasi tip

definit de delegate.

Algoritmii complecsi sau reutilizati ar trebui implementati in cadrul metodelor cu nume si nu in cadrul

delegates anonimi sau expresii lambda.

Page 8: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Expression Trees

Eexpression trees : data este reprezentata sub forma de arbore ca rezultat al unui operator de cereri,

operator dat sub forma unei expresii lamba.

Evaluarea se face simultan si nu secvential.

Exemplu (nu e sub forma unei cereri – expression trees) forma C#

int[] nums = new int[] { 6, 2, 7, 1, 9, 3 }; IEnumerable<int> set4 = nums .Where(i => i < 4) .OrderBy(i => i);

Se executa mai intai Where si apoi OrderBy (secvential).

Ce emite compilatorul ?

Daca operatorul (Where in cazul nostru) este declarat sa accepte un delegate, atunci se emite cod IL.

Daca operatorul este declarat sa accepte o expresie a unei metode delegate, se emite o expresie tree.

Sa vedem cum este definit operatorul Where.

Este in clasa System.Linq.Enumerable (Linq to Objects):

public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate);

O alta implementare este in Linq to SQL in clasa System.Linq.Queryable:

public static IQueryable<T> Where<T>( this IQueryable<T> source, System.Linq.Expressions.Expression<Func<int, bool>> predicate);

Prima forma produce cod IL, iar a doua forma produce expression trees.

var

Cuvantul cheie var permite ca tipul de data al unui obiect sa fie acelasi cu tipul obiectului folosit la

initializare.

Trebuie initializat in momentul crearii.

var mv = new { Nume = "Ionescu", Prenume = "Ion"} ; var anonim = new {Nume = "Ionescu", Inaltime = 1.85, Varsta = 20}; // string, float, int

Console.WriteLine(anonim.Nume);

In exemplul de mai sus am definit un tip anonim ce contine doua date membru: Nume si Prenume.

Acest tip de data nu are nici un nume.

Page 9: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Tipurile anonime sunt foarte des utilizate in operatorii Select sau SelectMany. Daca nu ar exista

aceste tipuri ar trebui sa construim cate o clasa pentru fiecare expresie pe care dorim sa o folosim. Vezi

ex cu clasa TipAnonim.

Query Expressions – expresii pentru creare cereri Query expressions permit cererilor LINQ sa fie scrise intr-o forma asemanatoare cu cea data de SQL.

Cerere scrisa in sintaxa .NET:

string[] names = {

"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland", "Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield", "Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson", "Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley", "Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft", "Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};

IEnumerable<string> sequence = names .Where(n => n.Length < 6) .Select(n => n); foreach (string name in sequence) {

Console.WriteLine("{0}", name); }

iar echivalentul folosind query expressions este:

IEnumerable<string> sequence = from n in names where n.Length < 6 select n;

Page 10: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Reguli pentru expresii :

1. O expresie trebuie sa inceapa cu clauza from. 2. Ceea ce urmeaza poate sa contina zero sau mai multe clauze from, let sau where. O clauza

from este un generator ce declara una sau mai multe variabile enumerator, variabile ce

enumereaza peste un sir sau un join de mai multe siruri.

3. In continuare se poate folosi clauza orderby.

4. Restul expresiei poate fi urmat de clauza select sau group iar in final optional clauza into

sau zero sau mai multe clauze join sau din nou 2.

Pentru mai multe detalii consultati documentatia din MSDN privitoare la LINQ.

query-expression:

from-clause query-body

from-clause:

from typeopt identifier in expression join-clausesopt

join-clauses:

join-clause

join-clauses join-clause

join-clause:

join typeopt identifier in expression on expression equals

expression

join typeopt identifier in expression on expression equals

expression into identifier

query-body:

from-let-where-clausesopt orderby-clauseopt select-or-group-clause

query-continuationopt

from-let-where-clauses:

from-let-where-clause

from-let-where-clauses from-let-where-clause

from-let-where-clause:

from-clause

let-clause

where-clause

let-clause:

let identifier = expression

where-clause:

where boolean-expression

orderby-clause:

orderby orderings

orderings:

ordering

orderings , ordering

ordering:

expression ordering-directionopt

ordering-direction:

ascending

Page 11: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

descending

select-or-group-clause:

select-clause

group-clause

select-clause:

select expression

group-clause:

group expression by expression

query-continuation:

into identifier join-clausesopt query-body

Linq to Objects

IEnumerable<T>, secvente si operatorii de cereri standard

IEnumerable<T>, este o interfata pe care o implementeaza toate colectiile generice din C# 2.0.

Aceasta interfata permite enumerarea elementelor din colectie. Vezi Colectii generice de pe pagina

http://www.infoiasi.ro/~iasimin.

O secventa este un termen logic pentru o colectie ce implementeaza interfata IEnumerable<T>.

Daca avem o variabila de tipul IEnumerable<T>, atunci putem spune ca avem un sir (o secventa) de

elemente de tipul T.

Majoritatea operatorilor standard de cereri ( Standard Query Operators ) sunt metode extinse pe clasa

statica System.Linq.Enumerable si au ca prim argument IEnumerable<T>. Din cauza ca sunt

metode extinse, este de preferat sa le apelam pe variabile de tipul IEnumerable<T> in loc de a le

pasa in metoda ca primul argument.

Operatorii Cast<T>() si OfType<T>() – folositi pentru a face conversia colectiilor la IEnumerable<T>.

Se folosesc pentru colectii ce nu implementeaza IEnumerable<T>.

Cast incearca sa faca conversia tuturor elementelor existente si daca exista un element pe care esueaza

va genera o exceptie.

OfType va pune numai acele elemente pentru care conversia reuseste.

Page 12: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

“Returning IEnumerable<T>, Yielding, and Deferred Queries”

Din cauza ca aceste tipuri de cereri ce returneaza IEnumerable<T> definesc numai prototipul cererii,

putem scrie codul ce defineste cererea o singura data si folosim aceasta cerere de mai multe ori in

enumerarea elementelor.

// Creaza un tablou de int. int[] intArray = new int[] { 1,2,3 }; IEnumerable<int> ints = intArray.Select(i => i);

// Afiseaza rezultatele. foreach(int i in ints) Console.WriteLine(i);

// Schimba un element in sursa de date. intArray[0] = 5; Console.WriteLine("---------");

// Afiseaza rezultatele din nou. foreach(int i in ints) Console.WriteLine(i);

Am creat cererea o singura data si o apelam de mai multe ori. Daca nu ar fi asa, rezultatul enumerarii

ar fi fost identic in cele doua cazuri.

Daca vrem ca cererea sa nu fie « amanata » la executie putem folosi unul din operatorii de conversie

ce nu returneaza un IEnumerable<T>.

Acestia sunt : ToArray, ToList, ToDictionary sau ToLookup.

Exemplu:

// Creaza un tablou de int. int[] intArray = new int[] { 1, 2, 3 }; List<int> ints = intArray.Select(i => i).ToList(); // Afiseaza rezultatele. foreach(int i in ints) Console.WriteLine(i); // Schimba un element in sursa de date. // Modificarea nu este vazuta pentru ca cererea nu este reimprospatata (deferred) intArray[0] = 5; Console.WriteLine("---------"); // Afiseaza rezultatele din nou. foreach(int i in ints) Console.WriteLine(i);

Page 13: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Delegates de tip Func

Multi dintre operatorii standard de cereri au in prototipul lor un argument de tip delegate, numit Func.

Acest lucru ne scuteste de a declara in mod explicit un tip delegate.

public delegate TR Func<TR>(); public delegate TR Func<T0, TR>(T0 a0); public delegate TR Func<T0, T1, TR>(T0 a0, T1 a1); public delegate TR Func<T0, T1, T2, TR>(T0 a0, T1 a1, T2 a2); public delegate TR Func<T0, T1, T2, T3, TR>(T0 a0, T1 a1, T2 a2, T3 a3);

TR se refera la tipul de data returnat.

Exemplu

Prototipul pentru operatorul Where este (exista doua prototipuri):

public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate);

Observam ca este metoda extinsa pentru IEnumerable<T>.

Argumentul predicat este specificat ca Func<T, bool>. De aici observam ca metoda predicate sau

lambda expresia accepta un singur argument, parametrul T si returneaza un bool. Tipul returnat este

ultimul in lista de parametri.

Ex // Cream un array de int int[] ints = new int[] { 1,2,3,4,5,6 }; // Declaram delegate Func<int, bool> MaiMareCaDoi = i => i > 2; // Declaram codul pentru cerere ... va fi “deferred” IEnumerable<int> result = ints.Where(MaiMareCaDoi); // Afisare rezultat foreach(int i in result)

Console.WriteLine(i); Rezultat: 3, 4, 5, 6

Page 14: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Table 3-1. Standard Query Operators Alphabetical Cross-Reference

Page 15: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Page 16: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Namespace-urile necesare sunt:

using System.Linq; using System.Collections; using System.Collections.Generic; using System.Data.Linq;

Operatori de restrictii

Where : filtreaza elementele dintr-un sir.

public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate);

public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, int, bool> predicate);

In: source – contine sirul de elemente;

predicate – metoda delegate folosita pentru filtrare.

int – reprezinta indexul elementului din sirul de intrare - source (zero based).

Out: obiecte pentru care predicate a returnat true.

Exceptii: ArgumentNullException – daca exista un argument null.

Ex string[] orase = {“Iasi”, “Vaslui”, “Botosani”, “Cluj”, “Timisoara”, “Bacau”}; // orasele ce incep cu litera I

IEnumerable<string> sir = orase.Where(o => o.StartsWith(“I”)); foreach(string s in sir)

Console.WriteLine(s); // se extrag din sir elementele plasate pe locuri impare IEnumerable<string> sirimpar = orase.Where((o,i) => (i &1) == 1);

Page 17: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

foreach(string s in sirimpar) Console.WriteLine(s);

Ex. Din colectia carti se extrag acele elemente pentru care proprietatea Pret >= 10.

IEnumerable<Carti> x = carti.Where(p => p.Pret >= 10);

In C# 3.0 query expression arata astfel:

IEnumerable<Carti> x = from p in carti where p.Pret >= 10 select p;

carti – reprezinta colectia de Carti (vezi exemplul de cod). (SQL: Select * From carti p Where p.Pret >= 10).

Proiectie

Operatorii de proiectie returneaza un sir de elemente ce sunt generate prin selectarea elementelor sau

instantierea impreuna a noi elemente ce contin portiuni ale elementelor din sirul de intrare.

Tipul de data al elementelor din sirul de iesire poate fi diferit de tipul de data al elementelor din sirul

de intrare.

Select – folosit pentru a crea un sir de iesire de un anumit tip folosind in intrare un sir de un alt tip. public static IEnumerable<S> Select<T, S>( this IEnumerable<T> source, Func<T, S> selector);

public static IEnumerable<S> Select<T, S>( this IEnumerable<T> source, Func<T, int, S> selector);

In intrare avem tipul T, in iesire avem tipul S. Metoda delegate selector este folosita pentru a face

selectia.

Exceptii: ArgumentNullException – daca exista un argument null.

Exemplu:

IEnumerable<int> nrcar = orase.Select(o => o.Length) ; foreach(int i in nrcar)

Console.WriteLine({0}, i); var items = orase.Select((o, i) => new { oras = o, nc = o.Length} ); foreach(var v in items)

Console.WriteLine(“ Oras : {0} are {1} caractere in nume”, v.oras,v.nc);

SelectMany – creaza o proiectie de 1-n. Returneaza zero sau mai multe elemente pentru fiecare

element din intrare.

Page 18: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

public static IEnumerable<S> SelectMany<T, S>( this IEnumerable<T> source, Func<T, IEnumerable<S>> selector);

public static IEnumerable<S> SelectMany<T, S>( this IEnumerable<T> source, Func<T, int, IEnumerable<S>> selector);

In intrare un element de tip T, in iesire un element de tip S, iar delegate este dat de selector.

Pentru fiecare element din sirul de intrare va rezulta un element concatenat in iesire.

Exceptii: ArgumentNullException – daca exista un argument null.

IEnumerable<char> chars = orase.SelectMany(o => o.ToArray()); foreach (char ch in chars)

Console.WriteLine(ch);

Folosind clasele Scriitori si Carti putem crea urmatoarea colectie :

// Colectiile de mai jos au in comun o data membru id Scriitori[] scriitori = Scriitori.GetScriitori(); Carti[] carti = Carti.GetCarti(); var items = scriitori .OrderBy(s => s.Nume) .SelectMany(e => carti .Where(eo => eo.id == e.id) .Select(eo => new

{ id = eo.id, Nume = e.Nume, Prenume = e.Prenume, titlu = eo.Titlu } ));

foreach (var item in items) Console.WriteLine(item);

(SQL: Select eo.id, e.Nume, e.Prenume, eo.Titlu From carti eo, scriitori e

Where eo.id = e.id

Order by e.Nume)

Page 19: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Partitionare – acesti operatori ne permit sa returnam un sir ce este o submultime a sirului de intrare.

Take – returneaza un numar specificat de elemente din sirul de intrare plecand de la inceputul

sirului.

public static IEnumerable<T> Take<T>( this IEnumerable<T> source, int count);

In : count – specifica cate elemente trebuie sa luam din sirul de intrare, incepand cu primul element.

Ex : IEnumerable<string> items = orase.Take(5);

TakeWhile – returneaza elemente din sirul de intrare atata timp cat conditia este adevarata.

public static IEnumerable<T> TakeWhile<T>( this IEnumerable<T> source, Func<T, bool> predicate); public static IEnumerable<T> TakeWhile<T>( this IEnumerable<T> source, Func<T, int, bool> predicate);

Exceptii: ArgumentNullException

Skip – se vor sari atatea elemnete din sirul de intrare cate sunt specificate in count.

public static IEnumerable<T> Skip<T>( this IEnumerable<T> source, int count);

Exceptii: ArgumentNullException

SkipWhile – se vor sari elementele din intrare pana cand conditia devine false.

public static IEnumerable<T> SkipWhile<T>( this IEnumerable<T> source, Func<T, bool> predicate); public static IEnumerable<T> SkipWhile<T>( this IEnumerable<T> source, Func<T, int, bool> predicate);

Exceptii: ArgumentNullException

Concatenare – acesti operatori permit concatenarea sirurilor de acelasi tip.

Concat – concateneaza doua siruri de intrare si rezulta un singur sir.

public static IEnumerable<T> Concat<T>( this IEnumerable<T> first, IEnumerable<T> second);

Page 20: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

Ex:

IEnumerable<string> items = orase.Take(2).Concat(orase.Skip(1));

Ordonarea

Operatorii OrderBy si OrderByDescending au ca parametru de intrare un sir de tip

IEnumerable<T> si returneaza un sir de tip IOrderedEnumerable<T>. Deci nu putem folosi in

intrare o iesire de la OrderBy sau OrderByDescending.

Daca dorim ordonari dupa mai multe campuri vom folosi ThenBy si/sau ThenByDescending,

operatori ce permit ca sirul de intrare sa fie de tip IOrderedEnumerable<T>.

Ex. eronat:

inputSequence.OrderBy(s => s.LastName).OrderBy(s => s.FirstName)…

Ex. corect

inputSequence.OrderBy(s => s.LastName).ThenBy(s => s.FirstName)…

OrderBy / OrderByDescending (acelasi prototip)

public static IOrderedEnumerable<T> OrderBy<T, K>( this IEnumerable<T> source, Func<T, K> keySelector)

unde (deci K trebuie sa fie un tip ce suporta o relatie de ordine): K : IComparable<K>; public static IOrderedEnumerable<T> OrderBy<T, K>(

this IEnumerable<T> source, Func<T, K> keySelector, IComparer<K> comparer);

Pentru prototipul 2 nu este necesar ca tipul K sa implementeze interfata IComparable. Se foloseste

delegate comparer. In acest caz putem furniza metoda noastra ce va face compararea.

Interfata IComparer este definita astfel:

interface IComparer<T> {

int Compare(T x, T y); }

deci noi va trebui sa scriem cod pentru metoda Compare.

ThenBy / ThenByDescending – aceleasi observatii ca la OrderBy

public static IOrderedEnumerable<T> ThenBy<T, K>( this IOrderedEnumerable<T> source, Func<T, K> keySelector)

unde: K : IComparable<K>;

Page 21: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

public static IOrderedEnumerable<T> ThenBy<T, K>( this IOrderedEnumerable<T> source, Func<T, K> keySelector, IComparer<K> comparer);

Ex: IEnumerable<string> items = orase.OrderBy(s => s.Length).ThenBy(s => s);

Reverse – returneaza acelasi sir dar in ordine inversa.

public static IEnumerable<T> Reverse<T>( this IEnumerable<T> source);

Join - join pe mai multe siruri.

public static IEnumerable<V> Join<T, U, K, V>(

this IEnumerable<T> outer, IEnumerable<U> inner, Func<T, K> outerKeySelector, Func<U, K> innerKeySelector, Func<T, U, V> resultSelector);

Operatorul Join va returna un obiect care in timpul enumerarii va enumera mai intai elementele din

sirul inner de tip U, apeland metoda innerKeySelector odata pentru fiecare element si memoreaza

elementul, referit de cheia sa, intr-o tabela hash. In continuare, obiectul returnat va enumera sirul outer

de elemente de tip T pe care se va apela metoda outerKeySelector pentru a obtine cheia si a regasi

elementele din sirul inner ce se potrivesc. Obiectul returnat va apela metoda resultSelector ce primeste

atat elementele din outer cat si cele din inner. Aceasta metoda returneaza un tip V.

Exceptii: ArgumentNullException.

Scriitori[] scriitori = Scriitori.GetScriitori(); Carti[] carti = Carti.GetCarti(); Console.WriteLine("\nPrintJoin ... "); var items = scriitori .Join( carti, // inner sequence e => e.id, // outerKeySelector o => o.id, // innerKeySelector (e, o) => new // resultSelector { id = e.id, nume = string.Format("{0} {1}", e.Nume, e.Prenume), pret = o.Pret }); foreach (var item in items) Console.WriteLine(item);

Page 22: Cuprins Expresii lambda (Lambda expressions). Arbori de ...iasimin/csharp/C11_LINQ.pdf · LINQ to SQL – API IQuerable ce permite Linq sa lucreze cu SQL Server si nu

LINQ - Language Integrated Query 05.01.2014

Ioan Asiminoaei

GroupJoin

Operatorul GroupJoin efectueaza o grupare a doua siruri, grupare bazata pe o cheie definita in cadrul

elementelor sirului.

public static IEnumerable<V> GroupJoin<T, U, K, V>( this IEnumerable<T> outer, IEnumerable<U> inner, Func<T, K> outerKeySelector, Func<U, K> innerKeySelector, Func<T, IEnumerable<U>, V> resultSelector);

Argumentele outerKeySelector si innerKeySelector specifica functiile ce extrag valorile cheii

dupa care se face join, din sirul outer respectiv inner.

Argumentul resultSelector specifica o functie ce creaza un element al rezultatului folosind

elemente din inner si outer.

Cand este enumerat obiectul returnat de GroupJoin, mai intai se enumera elementele din sirul inner si

se evalueaza functia innerSelector odata pentru fiecare element, colectand elementele intr-o tabela

hash.

Dupa ce au fost colectate elementele in tabela hash, sirul outer este enumerat. Pentru fiecare element

din acest sir se evalueaza functia outerSelector, iar cheia ce rezulta se cauta in tabela hash a

elementelor din inner si apoi este evaluata functia resultSelector ce va furniza elementul sau daca nu

exista potrivire nu se returneaza nimic..

Nu exista echivalent in SQL pentru aceasta functie.