cuprins expresii lambda (lambda expressions). arbori de ...iasimin/csharp/c11_linq.pdf · linq to...
TRANSCRIPT
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.
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>");
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); }
}
...
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); }
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.
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);
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.
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.
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;
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
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.
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);
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
LINQ - Language Integrated Query 05.01.2014
Ioan Asiminoaei
Table 3-1. Standard Query Operators Alphabetical Cross-Reference
LINQ - Language Integrated Query 05.01.2014
Ioan Asiminoaei
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);
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.
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)
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);
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>;
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);
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.