Adottak a következő osztályok, és listák ilyen objektumokból.
class Product
{
public int ID;
public string Name;
public int Price;
public int VATID;
}
class VAT
{
public int ID;
public int Percentage;
}
List<Product> products = ...
List<VAT> vat = ...
!!! important "System.Linq
"
A Linq használatához a System.Linq
névteret kell használnunk:
```csharp
using System.Linq;
```
Az alábbi példáknál, ahol elérhető, mindkét szintaktikát mutatjuk. A két féle szintaktika teljesen egyenértékű.
products.Where(p => p.Price < 1000)
from p in products
where p.Price < 1000
products.Select(p => p.Name)
from p in products
select p.Name
from p in products
join v in vat on p.VATID equals v.Id
select p.Price * v.Percentage
products.Join(vat, p => p.VATID, v => v.Id, (p, v) => p.Price * v.Percentage)
products.OrderBy[Descending](p => p.Name)
.ThenBy[Descending](p => p.Price)
from p in products
orderby p.Name, p.Price [descending]
products.Select(p => p.Name).Distinct()
products.Where(p => p.Price < 1000)
.Union( products.Where(p => p.Price > 100000) )
// hasonlóan Except, Intersect
products.Count()
products.Select(p => p.Price).Average()
// hasonlóan Sum, Min, Max
products.First()
products.Last()
products.Where(p => p.Id==12).FirstOrDefault()
products.Where(p => p.Id==12).SingleOrDefault()
products.Take(10)
products.Skip(10).Take(10)
products.Any(p => p.Price == 1234)
products.Where(p => p.Price == 1234).Any()
from p in products
group p by p.VATID
products.GroupBy(p => p.VATID)
A projekció során több féle módon kérhetjük az eredményeket.
from p in products
...
select p
Ilyenkor az eredmény IQueryable<Product>
, azaz Product osztály példányokat kapunk.
from p in products
...
select p.Name
Ilyenkor az eredmény IQueryable<string>
, azaz csak a neveket kapjuk.
from p in products
...
select new MyType(p.Name, p.Price)
Ilyenkor az eredmény IQueryable<MyType>
, ahol a MyType osztályt deklarálnunk kell, és a select-ben a konstruktorát hívjuk meg.
from p in products
where p.Price > 1000
select new { ID = p.ID, Name = p.Name };
Névtelen típust a new { }
szintaktikával hozhatunk létre. Ebből a fordító egy osztály definíciót készít a megadott nevű property-kkel. Ezt tipikusan akkor érdemes használni, ha egy-két tulajdonságot szeretnénk csak lekérdezni, és nincs szükségünk az egész objektumra.
Egy másik gyakori használati esete a névtelen típusnak, amikor nem egy rekord pár tulajdonságára vagyunk kíváncsiak, hanem számított értéket kérdezünk le, pl. a termékek neve és bruttó ára:
from p in products
join v in vat on p.VATID equals v.Id
select new { Name = p.Name, FullPrice = p.Price * (1 + v.Percentage / 100) }
Annak függvényében, hogy a Linq műveleteket milyen adatforráson használjuk, a products.Where(p => p.Price < 1000)
jellegű kifejezések eredménye IEnumerable<T>
vagy IQueryable<T>
. Mindkettőre igaz, hogy az eredményhalmaz helyett csak leírók, azaz a művelet még nem került végrehajtásra. Ezt késői kiértékelésnek (deferred execution) hívjuk, ugyanis a leírt művelet csak akkor fog végrehajtódni, amikor az eredményekre ténylegesen is szükség van:
- amikor elkezdünk iterálni az eredményhalmazon (pl.
foreach
), - amikor elkérjük az első elemet (lásd később, pl.
.First()
), - amikor listát kérünk az eredményhalmazból (
.ToList()
).
Ez a működés azért praktikus, mert így tudjuk szintaktikailag egymás után fűzni a LINQ műveleteket, mint például:
var l = products.Where(p => p.Price < 1000)
.Where(p => p.Name.Contains('s'))
.OrderBy(p => p.Name)
.Select(p => p.Name)
...
// az l változó nem tartalmazza az eredményhalmazt
foreach(var x in l) // itt fog lefutni a tényleges kiértékelés
{ ... }
!!! note "Kiértékelés"
Ha mindenképpen szeretnénk kérni a lefuttatást, akkor tipikusan a .ToList()
-et használjuk. Ezzel azonban vigyázzunk, fontoljuk meg, tényleg erre van-e szükségünk.
Lambda kifejezések: https://www.tutorialsteacher.com/linq/linq-lambda-expression
Linq: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/