1. Giriş
Təsəvvür elə ki, sən balaca bir mağazanın sahibisən və səndə məhsulların siyahısı var. Hər məhsulun özünəməxsus artikulu var (məsələn, ART-001, ART-002) və əlbəttə ki, adı, qiyməti, anbarda olan miqdarı.
Əgər sən bunların hamısını List<T>-də saxlasaydın, burada T məsələn, gələcək Product sinfimiz olsaydı, ART-005 artikullu məhsulu tapmaq üçün bütün siyahını bir-bir yoxlamalı olardın:
"Bu ART-001-dir? Yox. Bu ART-002-dir? Yox... Bəs bu ART-005-dir! Tapdım!"
10 məhsul olanda problem deyil. Bəs 10 000 məhsul? Yaxud 100 000? Hər məhsulu tapmaq üçün çox vaxt gedəcək. Müştəri sənin onun sevimli peçenye paketini tapmağını çox gözləməli olacaq. Belə olmaz!
Bizə elə bir üsul lazımdır ki, unikal artikulu biləndə, bütün siyahını bir-bir yoxlamadan, birbaşa lazım olan məhsula keçə bilək. Yəni, bizə bir "açar" lazımdır ki, birbaşa "dəyərə" işarə etsin.
Dictionary ilə tanışlıq
Və burada səhnəyə Dictionary<TKey, TValue> çıxır! Təsəvvür elə ki, bu sadəcə siyahı deyil, çox ağıllı telefon kitabçasıdır. Adi telefon kitabçasında sən telefon nömrəsini (dəyər) insanın adına (açar) görə axtarırsan. Kitabı "A" hərfində açırsan, sonra "Aleksey"i tapırsan və budur, onun nömrəsi. Sənə lazım olan nömrəni tapana qədər bütün nömrələri bir-bir vərəqləməyə ehtiyac yoxdur.
Eynilə Dictionary (yəni ingiliscədən tərcümədə "Lüğət") məlumatları "açar-dəyər" cütləri şəklində saxlayır.
- Açar (TKey): Hər element üçün unikal identifikatordur. Telefon kitabçasında ad, məhsulda isə artikul kimidir. Bu açarla sən lazım olan dəyəri tapacaqsan. Açar unikal olmalıdır. Eyni açarla element əlavə etməyə çalışsan, Dictionary buna imkan verməyəcək.
- Dəyər (TValue): Saxlamaq istədiyin məlumatın özüdür. Bu, telefon nömrəsi, məhsulun qiyməti, termin izahı və s. ola bilər!
TKey və TValue hərfləri <TKey, TValue> bucaqlı mötərizələrində yazılıb, çünki Dictionary generik (Generic) kolleksiyadır. Sən özün seçirsən, açarın tipi nə olacaq, dəyərin tipi nə olacaq. Açar kimi string (ad, artikul), int (istifadəçi ID-si), hətta öz sinfin də ola bilər. Dəyər isə int, string, double və ya yenə də obyekt ola bilər.
Üstünlüyü? Anında çıxış! Xüsusi daxili quruluşuna görə (hash-table, elmi desək, amma hələlik necə işlədiyini bilməyə ehtiyac yoxdur), Dictionary açara görə dəyəri çox qısa vaxtda tapmağa imkan verir, fərqi yoxdur, lüğətdə on element var, yoxsa milyon. Bu, böyük kitabxanada super-indeks kimidir: sən deyirsən "mənə C# kitabı lazımdır", dərhal göstərirlər haradadır, hər rəfi bir-bir axtarmırsan.
Gəlin dərhal işə başlayaq! Biz layihəmizi inkişaf etdirəcəyik, interaktiv "C# terminləri lüğəti" yaradacağıq, bu da bizə yeni anlayışları yadda saxlamağa kömək edəcək.
2. Sintaksisin əsasları: lüğət yaradırıq
Hər şey klassik başlayır: dəyişən elan edirik, amma indi bir yox, iki tip göstəririk — açarın tipi (TKey) və dəyərin tipi (TValue):
// Sadə lüğət: açar - string (login), dəyər - string (email)
Dictionary<string, string> userEmails = new Dictionary<string, string>();
// Və ya qısa şəkildə var ilə
var userEmails = new Dictionary<string, string>();
Niyə mütləq hər iki tipi göstərmək lazımdır?
Çünki C# ciddi tipli dildir və lüğət bilməlidir ki, sən ona hansı açar və dəyər tipləri hazırlamısan.
Elementlərin əlavə olunması
Yeni "açar-dəyər" cütü əlavə etmək üçün Add metodundan istifadə edirik. Açar unikal olmalıdır!
userEmails.Add("vasya", "vasya@example.com");
userEmails.Add("petya", "petya@gmail.com");
Eyni açarla yenidən əlavə etməyə çalışsan — lüğət inciyəcək və istisna atacaq.
Dəyərlərə açar ilə çıxış
Lüğətin ən gözəl tərəfi — açarla dəyəri almaqdır:
string email = userEmails["vasya"];
Console.WriteLine(email); // vasya@example.com
Əgər mövcud olmayan açarla müraciət etsən, proqram dərhal qışqıracaq (KeyNotFoundException istisnası atacaq). Təhlükəsiz işləmək üçün tezliklə açarın olub-olmadığını yoxlamaq metodlarına baxacağıq.
Açar üzrə dəyərin dəyişdirilməsi
Əgər belə açar artıq varsa, sadəcə yeni dəyər təyin edirik:
userEmails["vasya"] = "vasya@newmail.ru"; // indi Vasyanın emaili dəyişdi
Əgər açar yoxdursa — belə təyinat lüğətə yeni element əlavə edəcək.
İstifadəçilərlə nümunə
Gəlin tədris tətbiqimizi bir az təkmilləşdirək. Bizdə ToDo proqramı üçün tapşırıqlar siyahısı (List<string> tasks;) var idi. İndi isə "avtorizasiya" əlavə etmək istəyirik: hər istifadəçiyə email lazımdır.
Bu belə görünə bilər:
// UserId — string, Email də string
var users = new Dictionary<string, string>();
users.Add("admin", "admin@myapp.com");
users.Add("alice", "alice@wonderland.com");
users.Add("bob", "bob@builder.com");
İndi istənilən istifadəçinin emailini loginə görə tez tapa bilərsən:
Console.WriteLine(users["alice"]); // => alice@wonderland.com
3. Dictionary-nin əsas metod və xüsusiyyətləri
| Metod/Xüsusiyyət | Təsviri |
|---|---|
|
Yeni "açar-dəyər" cütü əlavə edir. |
|
Açar üzrə elementi silir. |
|
Belə açar olub-olmadığını yoxlayır. |
|
Belə dəyər olub-olmadığını yoxlayır (yavaşdır!). |
|
Açar üzrə dəyəri təhlükəsiz almaq, istisna atmadan. |
|
Lüğətdəki "açar-dəyər" cütlərinin sayı. |
|
Bütün açarların kolleksiyası. |
|
Bütün dəyərlərin kolleksiyası. |
Açarın olub-olmadığını yoxlamaq
Ən yayılmış (və təhlükəsiz) üsul — əvvəlcə açarın olub-olmadığını yoxlamaqdır:
if (users.ContainsKey("dasha"))
{
Console.WriteLine(users["dasha"]);
}
else
{
Console.WriteLine("İstifadəçi dasha tapılmadı!");
}
Təhlükəsiz üsul: TryGetValue
TryGetValue metodu istisna atmamağa imkan verir:
if (users.TryGetValue("bob", out string email))
{
Console.WriteLine($"Bob-un poçtu: {email}");
}
else
{
Console.WriteLine("Bob tapılmadı!");
}
Bu yaxşı praktikadır və hətta müsahibələrdə də tez-tez soruşurlar — dərhal öyrən! Üstəlik, bu metod ContainsKey + indekslə müraciətdən daha sürətlidir.
4. Lüğətin dövrü: foreach dövrü
Bütün cütlər üzrə keçmək lazımdırsa, foreach dövründən istifadə et. Hər lüğət elementi KeyValuePair<TKey, TValue> tipində obyekt olur:
foreach (var pair in users)
{
Console.WriteLine($"Login: {pair.Key}, Email: {pair.Value}");
}
Yaxud, bir az daha cool olmaq istəyirsənsə:
foreach (var (login, email) in users)
{
Console.WriteLine($"{login}: {email}");
}
// Bu sintaksis tuple deconstruction (C# 7+) sayəsində mövcuddur.
5. Dəyərlərin silinməsi və dəyişdirilməsi
İstifadəçini loginə görə silmək asandır:
users.Remove("alice");
Əgər belə açar yoxdursa — false qaytaracaq. Qorxmadan silməyə cəhd edə bilərsən, istisna atmayacaq.
İstifadəçinin emailini dəyişmək:
users["bob"] = "bob@constructor.com";
Əgər belə açar yoxdursa — yeni cüt yaranacaq!
6. Keys və Values köməkçi xüsusiyyətləri
Əgər yalnız loginlərin (açarların) və ya yalnız emaillərin (dəyərlərin) siyahısı lazımdırsa, Keys və Values kolleksiyalarından istifadə et:
foreach (string login in users.Keys)
{
Console.WriteLine("Login: " + login);
}
foreach (string email in users.Values)
{
Console.WriteLine("Email: " + email);
}
7. Lüğətin vacib nüansları
Açarlar unikal olmalıdır
Yəni iki eyni açar əlavə etmək olmaz. Cəhd etsən — istisna alacaqsan. Belə unikalıq məlumatların təhlükəsizliyini təmin edir: bir istifadəçinin iki e-maili ola bilməz (bir qeyd üçün).
Açar null ola bilməz (string üçün)
String-açarlar üçün null açar əlavə etməyə cəhd etsən, səhv (ArgumentNullException) alacaqsan. Əgər birdən açarın yoxdursa, düşün — bəlkə məlumatların məntiqində problem var.
Niyə lüğətdə axtarış belə sürətlidir?
Dictionary "qapağın altında" hash-table ilə qurulub. Yəni açarla axtarış bütün elementləri bir-bir yoxlamaq deyil, xüsusi "hash-funksiya"nı sürətlə hesablamaq və demək olar ki, birbaşa dəyərin olduğu hüceyrəyə çıxmaqdır.
Açar kimi nə istifadə etmək olar?
- Bərabərlik və unikal kod almaq ( Equals və GetHashCode() metodları) düzgün işləyən istənilən tip.
- Adətən bu string, int, Guid və ya öz tiplərindir (amma onda Equals/GetHashCode düzgün override etməyə diqqət et, yoxsa maraqlı bug-lar çıxacaq).
8. Lüğəti tətbiqə əlavə edirik
Bizim mini ToDo tətbiqimizdə istifadəçilər üçün lüğət əlavə edəcəyik və loginə görə email axtarış funksiyasını səhv emalı ilə birlikdə yazacağıq:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// İstifadəçilər lüğəti: login => email
var users = new Dictionary<string, string>
{
{ "admin", "admin@myapp.com" },
{ "alice", "alice@wonderland.com" },
{ "bob", "bob@builder.com" }
};
Console.WriteLine("Email axtarmaq üçün istifadəçi loginini daxil et:");
string login = Console.ReadLine();
// Email-in təhlükəsiz axtarışı
if (users.TryGetValue(login, out string email))
{
Console.WriteLine($"İstifadəçi {login}-in emaili: {email}");
}
else
{
Console.WriteLine($"İstifadəçi {login} tapılmadı.");
}
// Bütün istifadəçilər üzrə dövr
Console.WriteLine("\nBütün istifadəçilərin siyahısı:");
foreach (var pair in users)
{
Console.WriteLine($"{pair.Key} => {pair.Value}");
}
}
}
9. Tipik səhvlər və tələlər
Bəzən çox istəyirlər ki, belə etsinlər:
// Ümid edirlər ki, açar yoxdursa — hər şey yaxşı olacaq
string value = users["nonexistent"]; // Bam! KeyNotFoundException!
Unutma: əmin deyilsənsə ki, açar var, həmişə əvvəlcə yoxla (ContainsKey və ya TryGetValue).
Həmçinin unutma: dəyərlər üzrə dövr onların unikal olmasını təmin etmir! Eyni email iki loginə aid ola bilər (əgər dəyərlərin unikalığına nəzarəti itirsən).
Metodları da qarışdırırlar — məsələn, dəyərə görə silməyə çalışırlar:
users.Remove("bob@builder.com"); // Silməyəcək! Açar gözlənilir, dəyər yox.
GO TO FULL VERSION