CodeGym /Kurslar /C# SELF /LINQ-ya giriş və onun üstünlükləri

LINQ-ya giriş və onun üstünlükləri

C# SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Təsəvvür elə, kitabxanaya gəlmisən və sənə proqramlaşdırma ilə bağlı bütün kitabları tapmaq lazımdır, amma yalnız 2020-ci ildən sonra nəşr olunanları və müəllif adına görə sıralanmış şəkildə. Yəqin ki, hər rəfə qaçıb, hər kitabı əl ilə yoxlamazdın, düzdür? Sən kitabxanaçıdan kömək istəyərdin, çünki o, lazım olanı tez tapmağı bacarır.

LINQ (Language Integrated Query, yəni "Dilə inteqrasiya olunmuş sorğular") — bizim "ağıllı kitabxanaçımızdır", "SQL-motorumuzdur" (yəni, məlumatlara sorğu yazmaq üçün alət) birbaşa C#-ın içində!

LINQ-a belə bax: sən istədiyini necə yox, istədiyini təsvir edirsən. Yəni, "Birinci elementi götür, şərti yoxla, uyğundursa yeni siyahıya əlavə elə, sonra ikinciyə keç..." demək əvəzinə, sadəcə deyirsən: "Mənə qiyməti 1000-dən yuxarı olan bütün məhsulları ver." Qalanını C# özü ən effektiv şəkildə həll edir.

LINQ-un əsas ideyası: IEnumerable<T> interfeysini reallaşdıran istənilən məlumat mənbəyinə standart sorğu sintaksisi verməkdir. Bu superdir, çünki List<T>, massivlər, HashSet<T> — bunların hamısı IEnumerable<T>-i dəstəkləyir. Əgər məlumatların bazadadırsa, xüsusi kitabxanalar (məsələn, Entity Framework) sənin LINQ-sorğunu əsl SQL-ə çevirəcək!

LINQ C#-da artıq 10 ildən çoxdur ki, var. Bu, .NET-də məlumatlarla işləməyə yanaşmanı dəyişən əlamətdar hadisə idi. LINQ-dan əvvəl, kolleksiyaları filtrləmək, sıralamaq və çevirmək üçün çoxlu şablon kod yazmaq lazım idi. Və ya SQL-sorğularını sətir kimi yazırdın, amma onlar kompilyator tərəfindən yoxlanmırdı və run-time-da səhvlərə səbəb olurdu. LINQ "sorğu" konsepsiyasını birbaşa proqramlaşdırma dilinə gətirdi, onları tip-təhlükəsiz və daha oxunaqlı etdi.

Çoxları hesab edir ki, LINQ — C#-da Generics çıxdıqdan bəri ən böyük yeniliklərdən biridir.

2. LINQ-un üstünlükləri: Niyə hamı onu sevir?

Kodun qısa və oxunaqlı olması: Məsələn, böyük bazada qiyməti 1000-dən yuxarı olan məhsulları filtrləmək üçün əvvəllər bir neçə sətr kod yazmaq lazım idi. LINQ ilə bunu bir sətrdə edə bilərsən. Az kod — az potensial səhv, daha çox oxunaqlılıq və anlaşıqlılıq. Kod daha təbii dilə yaxın olur.
Proqramçı zarafatı: "Nə qədər az kod yazıram, bir o qədər az bug əlavə edə bilərəm." LINQ bu işdə köməkçindir!

Güclü və çevik: LINQ çoxlu əməliyyatlar təklif edir: filtrasiya (Where), proyeksiya (Select), sıralama (OrderBy), qruplaşdırma (GroupBy), aqreqasiya (Sum, Average), birləşdirmə (Join) və s. Bu əməliyyatları birləşdirərək mürəkkəb məlumat emalı məsələlərini həll edə bilərsən.

Tip-təhlükəsizlik: Bu çox vacibdir! SQL-sorğunu sətir kimi yazanda, kompilyator heç nə bilmir. Sütunun adında səhv etsən, proqram yalnız işləyərkən səhv verəcək. LINQ ilə isə C# kompilyatoru sənin sorğunu dərhal yoxlayır. Product obyektində olmayan sahəni soruşsan, kompilyator dərhal səhv göstərəcək. Sanki şəxsi korrektorum var, səhvlərini başqaları görməmişdən qabaq tutur.

Dilə inteqrasiya: LINQ-sorğular — hansısa "sehrli" sətirlər deyil. Bunlar tam C# konstruksiyalarıdır, tanış lambda ifadələrindən və tanış məlumat tiplərindən istifadə edir. Bu, LINQ-a keçidi çox rahat edir.

Gecikdirilmiş icra (Deferred Execution): Bu LINQ-un ən cool və bəlkə də ən çətin anlayışlarından biridir, amma çox vacibdir. Məsələ ondadır ki, LINQ-sorğu elə yazan kimi icra olunmur. O "yığılır" və sən həqiqətən nəticə istəyəndə (məsələn, foreach ilə dövrə başlayanda) işləyir. Bu, xüsusilə böyük məlumatlarla işləyəndə sorğuları optimallaşdırmağa imkan verir. Bu barədə daha ətraflı 166-cı mühazirədə danışacağıq. Hələlik sadəcə yadında saxla: LINQ ağıllıdır, artıq iş görmür.

Universallıq və genişlənəbilənlik: LINQ — təkcə yaddaşdakı siyahılar üçün deyil. Müxtəlif LINQ "provider"ləri var:

  • LINQ to Objects: yaddaşdakı kolleksiyalar üçün (List<T>, massivlər və s.).
  • LINQ to SQL / Entity Framework Core: SQL verilənlər bazası üçün (sənin LINQ-sorğuların SQL-sorğulara çevrilir).
  • LINQ to XML: XML sənədlərlə işləmək üçün.
  • Və bir çox başqaları.
    Bu o deməkdir ki, LINQ-u öyrəndikdən sonra müxtəlif mənbələrdən olan məlumatlarla eyni sorğu məntiqi ilə işləyə biləcəksən.

3. Kolleksiyalarla "köhnə üsulla" işləməyin problemi

LINQ-dan əvvəl C#-da kolleksiyalarla işləyən kod təxminən belə idi:


var products = new List<Product> { /* ... */ };

var expensive = new List<Product>();
foreach (var prod in products)
{
    if (prod.Price > 100)
        expensive.Add(prod);
}

expensive.Sort((a, b) => a.Price.CompareTo(b.Price));

foreach (var item in expensive)
    Console.WriteLine(item.Name);

Bu yanaşma tipikdir: əvvəlcə əl ilə filtrlə, sonra sırala — mütləq aralıq siyahı yarat. Məntiq nə qədər çoxdursa, kod, səhv və dəyişən də bir o qədər çox olur. Bütün bunlar mebel yığma sexini xatırladır: detallar var, amma yığmaq — əl işidir və yorucudur.

Dövrələr ölkəsində Alisa

Təsəvvür elə, səndə böyük bir istifadəçi siyahısı var və sən yalnız 18-dən böyük olan və Neonvil şəhərində yaşayanların adlarını, əlifba sırası ilə sıralanmış və ilk üçünü çıxarmaq istəyirsən. Sənə iç-içə dövrlər, şərtlər, sıralamalar, köməkçi siyahılar yazmaq lazım olacaq... və ya sadəcə LINQ istifadə edə bilərsən.

4. LINQ-sorğusu necə görünür? Sadə nümunələr

LINQ-un iki əsas sintaksisi var:

  • Method Syntax (metod-zənciri)
  • Query Syntax (SQL-ə bənzər dil)

Ən çox Method Syntax istifadə olunur, xüsusilə müasir layihələrdə. Bizim tətbiq nümunəsində belədir:


var expensive = products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Price)
    .Select(p => p.Name)
    .Take(3);

foreach (var name in expensive)
    Console.WriteLine(name);

Hər şey aydındır: filtr, sıralama, konkret sahənin seçilməsi, sayın məhdudlaşdırılması. Minimum kod — maksimum məna.

Eyni şey Query Syntax ilə


var expensive = from p in products
                where p.Price > 100
                orderby p.Price
                select p.Name;

foreach (var name in expensive.Take(3))
    Console.WriteLine(name);

Hər iki variant eyni nəticəni verir — hansını xoşlayırsansa onu seç (amma method-sintaksis daha çox istifadə olunur).

5. LINQ-un arxitekturası: qapağın altında nə var?

LINQ istənilən kolleksiya ilə işləyir, əsas odur ki, IEnumerable<T> (və ya IQueryable<T>, bu barədə sonra danışacağıq) interfeysini dəstəkləsin.

LINQ-un əsas komponentləri

Komponent Qısa təsvir
LINQ extension-klassları Statik metodlar (
Where
,
Select
,
OrderBy
və s.)
System.Linq.Enumerable
sinfində
Delegatlar Ən çox
Func<T, TResult>
Predicate<T>
istifadə olunur
Gecikdirilmiş icra Sorğu yalnız ilk dəfə dövrə salanda (məsələn,
foreach
ilə) hesablanır
Query Provider (LINQ to SQL, LINQ to Entities üçün) — metod zəncirini SQL-sorğulara və s. çevirir

Vizual sxem


Kolleksiya (List<Product>, T[], ...) 
      │
      ▼
LINQ-metodlar (Where, OrderBy, Select...)
      │
      ▼
Sorğu (IEnumerable<T>) 
      │
      ▼
Real icra (foreach, ToList, Count, ...)

6. Nümunə: tətbiqimizdə LINQ-zəncirinin addım-addım izahı

Yenidən Product sinfi ilə mini-tətbiqimizə qayıdırıq:


// Məhsul sinfi
class Product
{
    public string Name { get; set; }
    public double Price { get; set; }
}

Məhsulların siyahısı belədir:


var products = new List<Product>
{
    new Product { Name = "Pendir", Price = 250.5 },
    new Product { Name = "Çörək", Price = 30 },
    new Product { Name = "Süd", Price = 80 },
    new Product { Name = "Kofe", Price = 330 },
    new Product { Name = "Yağ", Price = 140 }
};

Tutaq ki, tapşırıq belədir: 100 avrodan baha olan bütün məhsulların adlarını ekrana çıxar, qiymətə görə sırala.

Köhnə üsul


var filtered = new List<Product>();
foreach (var p in products)
{
    if (p.Price > 100)
        filtered.Add(p);
}

filtered.Sort((a, b) => a.Price.CompareTo(b.Price));

foreach (var p in filtered)
    Console.WriteLine(p.Name);

LINQ üsulu


var expensive = products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Price)
    .Select(p => p.Name);

foreach (var name in expensive)
    Console.WriteLine(name);

Birinci sətrdə biz tapşırığın özünü təsvir edirik: "Qiyməti Price > 100 olanları filtrlə, qiymətə görə sırala, adlarını seç".

7. LINQ-un tez-tez istifadə olunan əməliyyatları və onların "köhnə üsul" analoqları

Əməliyyat "Köhnə üsul" məntiqi LINQ
Filtrasiya foreach + if + Add
Where
Proyeksiya (sahənin seçilməsi) foreach + Add(field)
Select
Sıralama Sort(comparer)
OrderBy
,
OrderByDescending
Unikal dəyərlər foreach + contains + Add
Distinct
Sayma foreach + counter++
Count
,
Count(predicate)
Şərtin yoxlanması foreach + if
Any
,
All
Birinci/sonuncunu tapmaq foreach + if + break
First
,
Last
,
FirstOrDefault
Say məhdudiyyəti foreach + sayğac + break
Take
,
Skip

8. Praktika: tətbiqə LINQ əlavə edirik

Gəlin tətbiqimizin əsas kodunu (Product siyahısı) götürək və LINQ ilə bir neçə faydalı əməliyyat edək.

Filtrasiya və sıralama


// 200 avrodan ucuz məhsulları seç və ada görə sırala
var cheapProducts = products
    .Where(p => p.Price < 200)
    .OrderBy(p => p.Name);

foreach (var p in cheapProducts)
    Console.WriteLine($"{p.Name}: {p.Price} avro");

Kolleksiyanın çevrilməsi (proyeksiya)


// Qiymətlərin siyahısını (double) al
var prices = products.Select(p => p.Price);

foreach (var price in prices)
    Console.WriteLine(price);

İlk uyğun elementi tapmaq


// Adı "K" ilə başlayan ilk məhsul
var firstK = products.FirstOrDefault(p => p.Name.StartsWith("K"));
Console.WriteLine(firstK?.Name ?? "Tapılmadı");

100 avrodan baha məhsulların sayını tapmaq


int count = products.Count(p => p.Price > 100);
Console.WriteLine($"Belə məhsullar: {count} ədəd.");

Bu mühazirədən başlayaraq, kolleksiyaları emal etmək, filtrləmək, lazım olan məlumatları seçmək, aqreqasiyalar və daha çox şey üçün LINQ-dan aktiv istifadə edəcəyik. LINQ-un yeni metodlarını və imkanlarını (o cümlədən .NET 9-un yeniliklərini!) yaxın mühazirələrdə öyrənəcəyik, hələlik isə — sadə sorğularla eksperiment aparmaqdan çəkinmə, bu alətin gücünü hiss et!

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION