CodeGym /Kurslar /C# SELF /Lüğət üçün kontrakt: IDict...

Lüğət üçün kontrakt: IDictionary<TKey, TValue>

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

1. Giriş

Təsəvvür elə: gizli pişik laboratoriyasında işə düzəlmisən. Sənə tapşırıq verirlər — pişiklərin elektron lüğətini yarat, orda ləqəblə tez bir zamanda pişiyin yaşı, rəngi və quyruğunun ölçüsünü öyrənmək olar. Hazır həll artıq var — bu Dictionary<string, Cat>-dır. Amma problem odur ki, sonradan rəis deyir ki, bəzi nadir cinslər üçün lüğət əlavə olunan ardıcıllığı saxlamalıdır, bəzən də xüsusi məntiqə görə silinməlidir.

Bəs əgər sənə elə bir metod yazmaq lazımdır ki, istənilən "pişik lüğəti" qəbul etsin? Hansı konkret class olmasının fərqi yoxdur — əsas odur ki, əsas "açar-dəyər" əməliyyatlarını dəstəkləsin. Bax, burada IDictionary<TKey, TValue> interfeysi işə düşür.

IDictionary<TKey, TValue> — .NET-də lüğətin nə olduğunu müəyyən edən ümumi kontraktdır. Bu konkret class deyil, interfeysdir, yəni istənilən real lüğətin dəstəkləməli olduğu qaydalar toplusudur:

  • Açar üzrə sürətli axtarış
  • "Açar-dəyər" cütlərinin əlavə olunması və silinməsi
  • Bütün cütlərin üzərindən keçmək
  • Açarın olub-olmadığını yoxlamaq

Əgər Java Orta Əsrlərdə olsaydı, onun cəngavərləri əjdahaya qarşı qılınc əvəzinə açar və dəyərlərlə döyüşərdilər. Amma C# proqramçıları sadəcə IDictionary<TKey, TValue> implementasiya edərdi — və əjdaha (yəni sənin kodun) məğlub olardı.

2. IDictionary interfeysinin cədvəli

Gəlin bu interfeysin əsas "vəd"lərinə (üzvlərinə) baxaq:

İnterfeys üzvü Tip Təsviri
this[TKey key]
Xüsusiyyət İndeksator. Göstərilən açarla bağlı dəyəri almağa və ya təyin etməyə imkan verir. Oxuyanda: əgər açar tapılmasa, KeyNotFoundException atır. Yazanda: əgər açar tapılmasa, yeni cüt əlavə edir; əgər açar varsa, dəyəri yeniləyir. Vacibdir: lüğətlərlə işləyərkən ən çox istifadə olunan üsuldur.
ICollection<TKey> Keys
Xüsusiyyət Lüğətdəki bütün açarları saxlayan kolleksiyanı qaytarır. Yalnız açarların üzərindən keçməyə imkan verir.
ICollection<TValue> Values
Xüsusiyyət Lüğətdəki bütün dəyərləri saxlayan kolleksiyanı qaytarır. Yalnız dəyərlərin üzərindən keçməyə imkan verir.
Add(TKey key, TValue value)
Metod Göstərilən açar və dəyəri lüğətə əlavə edir. Əgər açar artıq varsa, ArgumentException atır.
ContainsKey(TKey key)
Metod Lüğətdə göstərilən açarla elementin olub-olmadığını müəyyən edir. Əgər açar tapılıbsa, true qaytarır; əks halda — false. Bu, indeksatorla mövcud olmayan açara müraciət edərkən səhvlərdən qaçmaq üçün çox faydalıdır.
Remove(TKey key)
Metod Lüğətdən göstərilən açarla elementi silir. Əgər element tapılıb və uğurla silinibsə, true qaytarır; əks halda — false (məsələn, açar tapılmayıbsa).
TryGetValue(TKey key, out TValue value)
Metod Göstərilən açarla bağlı dəyəri alır. Bu, dəyəri almaq üçün təhlükəsiz üsuldur, əgər açarın olub-olmadığına əmin deyilsənsə. Əgər açar tapılıbsa, true qaytarır və value uyğun dəyəri saxlayır; əks halda — falsevalue TValue üçün default dəyər olacaq. Bu metod istisna atmır, ona görə real kodda çox populyardır.

3. IDictionary<TKey, TValue> interfeysinin əsas üzvləri

İndi isə — ən vacib hissəyə! Gəlin IDictionary<TKey, TValue> interfeysinin içində nələr var, baxaq və bu "kontrakt"dan kodunda necə istifadə etməyi öyrənək.


public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
    TValue this[TKey key] { get; set; } // Açarla müraciət üçün indeksator
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    void Add(TKey key, TValue value); // Yeni cüt əlavə et (açar olmamalıdır) 
    bool ContainsKey(TKey key); // Belə açar var?
    bool Remove(TKey key); // Açarla sil
    bool TryGetValue(TKey key, out TValue value); // Təhlükəsiz dəyər almaq
}

Gəlin əsas məqamları aydınlaşdıraq:

[key] indeksatoru

Açarla dəyərləri almağa və təyin etməyə imkan verir:

dictionary["Barsik"] = new Cat("Barsik", 2);

KeysValues xüsusiyyətləri

Lüğətdəki bütün açarların və ya bütün dəyərlərin kolleksiyasını almağa imkan verir.

foreach (var name in dictionary.Keys)
{
    Console.WriteLine(name);
}

Add, Remove, ContainsKey, TryGetValue metodları

  • Add(key, value) — yeni cüt əlavə et
  • Remove(key) — açarla sil
  • ContainsKey(key) — açarın olub-olmadığını yoxla
  • TryGetValue(key, out value) — təhlükəsiz dəyər almaq (açar yoxdursa, istisna atmır)

4. IDictionary<TKey, TValue>-dən praktikada istifadə

Universal metodlar

Tutaq ki, sən elə bir funksiya yazırsan ki, lüğətlə işləməlidir, amma içində hansı class olduğunu bilmək istəmir: adi Dictionary, SortedDictionary, ya da kimsə öz "kriptokollektiv lüğətini" yazıb.

Parametri IDictionary<TKey, TValue> kimi elan edirsən:


static void PrintDictionary<TKey, TValue>(IDictionary<TKey, TValue> someDictionary)
{
    foreach (var pair in someDictionary)
    {
        Console.WriteLine($"{pair.Key}: {pair.Value}");
    }
}

İndi sənin metodun istənilən lüğəti qəbul edir! Altında nə istəsən ola bilər — hətta dəyərləri şifrələyən lüğət, əgər həyatın bu qədər maraqlıdırsa.

IDictionary-dən parametr ötürmək üçün istifadə

Tutaq ki, pişiklərin uçotu üçün app yazırsan və istəyirsən ki, metodun bütün mümkün ayar lüğətləri ilə işləsin, tək bir class ilə yox. Bax belə görünür:


void SetCatParameters(IDictionary<string, string> parameters)
{
    if (parameters.ContainsKey("color"))
    {
        Console.WriteLine($"Pişiyi rənglə: {parameters["color"]}");
    }
}

Bir imza — bir neçə implementasiya

Canlı cədvəldə izah edək:

Kolleksiya class-ı IDictionary<TKey,TValue> implementasiya edir Xüsusiyyətləri
Dictionary<TKey, TValue>
✅ Bəli Sürətli axtarış, açarlar təsadüfi ardıcıllıqla
SortedDictionary<TKey,TValue>
✅ Bəli Açarlar avtomatik sıralanır
SortedList<TKey, TValue>
✅ Bəli Açarlar sıralanır, yaddaşa daha qənaətcildir
(İnterfeysi implementasiya edən öz class-ın) ✅ Bəli İstənilən öz məntiqin, amma kontrakta əməl etməlisən

5. Digər kolleksiya interfeysləri ilə əlaqə

Həqiqi geeklər üçün: IDictionary<TKey, TValue> interfeysi ICollection<KeyValuePair<TKey, TValue>>IEnumerable<KeyValuePair<TKey, TValue>>-dən miras alır. Bu o deməkdir ki, istənilən lüğəti:

  • foreach ilə açar-dəyər cütləri üzrə gəzə bilərsən,
  • Kolleksiya metodları ilə cütləri əlavə və silə bilərsən,
  • Elementlərin sayını ala bilərsən.

foreach (var entry in myDictionary)
{
    Console.WriteLine($"{entry.Key} => {entry.Value}");
}

6. Xüsusiyyətlər və tipik səhvlər

İndeksatorla işləmək

Yeni başlayanların ən çox etdiyi səhv: mövcud olmayan açarla element almağa cəhd KeyNotFoundException atacaq.


var value = myDictionary["NemaTakogoAçara"]; // Boom!

Ona görə həmişə TryGetValue istifadə etmək daha yaxşıdır:


if (myDictionary.TryGetValue("Murzık", out var cat))
{
    Console.WriteLine($"Pişik tapıldı: {cat}");
}
else
{
    Console.WriteLine($"Pişik tapılmadı!");
}

Artıq mövcud açarı əlavə etmək

Əgər artıq olan açar üçün Add çağırsaq, ArgumentException alacaqsan. Əgər "əlavə et və ya yenilə" istəyirsənsə, indeksator istifadə et:


// Yoxdursa əlavə edir, varsa yeniləyir
myDictionary["Murka"] = new Cat("Murka", 5);

Üzərindən keçmək və dəyişmək

Lüğəti birbaşa foreach dövründə dəyişməyə (məsələn, elementləri silməyə) çalışmayın: istisna alacaqsan. Nə isə silmək lazımdırsa, əvvəlcə silinəcək açarların siyahısını topla, sonra ayrıca dövrdə sil:


// Elementləri silməyin təhlükəsiz yolu
var keysToRemove = new List<string>();
foreach (var pair in myDictionary)
{
    if (pair.Value.Age > 10) // Silmək üçün şərt
    {
        keysToRemove.Add(pair.Key);
    }
}

foreach (var key in keysToRemove)
{
    myDictionary.Remove(key);
}
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Kolleksiya üçün kontrakt
Kolleksiyaların əsas interfeysləri
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION