CodeGym /Kurslar /C# SELF /Sözlüklərin serializasiyası

Sözlüklərin serializasiyası

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

1. Giriş

Sözlük (və ya Dictionary<TKey, TValue> C#-da) — "açar-dəyər" cütlüklərindən ibarət kolleksiyadır. Bu tip məlumat strukturu unikal identifikatora görə dəyəri tez tapmaq lazım olanda əvəzolunmazdır (məsələn, telefon kitabında ada görə telefon nömrəsini tapmaq).

Siyahılarla (List<T>) fərqli olaraq, burada elementlərin sırası əhəmiyyətli deyil — sözlük açara görə sürətli çıxışa fokuslanır. Amma siyahının serializasiyası sadədir (JSON-massiv), sözlüyün serializasiyasında isə bir neçə nüans ortaya çıxır:

  • Açar serializasiya oluna bilən tipdə olmalıdır (çox vaxt string, amma bəzən ədəd və ya başqa obyekt də ola bilər).
  • JSON-da ayrıca "словарь" yoxdur — yalnız obyektlər və ya massivlər var.

Gəlin .NET-in sözlükləri necə serializasiya etdiyini, hansı problemlərlə üzləşə biləcəyimizi və kodumuzu bu strukturlarla düzgün işləməyə necə "öyrətmək" lazım olduğunu ətraflı nəzərdən keçirək.

2. String açarlı sözlüyün serializasiyası

Ən klassik haldan başlayaq — həm açar, həm dəyər string olan sözlük.


// Sözlük nümunəsi: kitab və onun müəllifi
var books = new Dictionary<string, string>
{
    ["Master i Margarita"] = "Mixail Bulgakov",
    ["Garri Potter"] = "Joan Rowling",
    ["Povelitel mukh"] = "Vilyam Golding"
};

// JSON sətrinə serializasiya
string json = JsonSerializer.Serialize(books, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine("Sözlük JSON-a serializasiya edildi:\n" + json);

// Fayla yazmaq (sinxron)
File.WriteAllText("books.json", json);
Console.WriteLine("JSON books.json faylına yazıldı.");

// Fayldan oxumaq (sinxron)
string jsonFromFile = File.ReadAllText("books.json");

// Yenidən sözlüyə deserialize
var restoredBooks = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonFromFile);
Console.WriteLine("Deserializasiya nəticəsi:");
foreach (var pair in restoredBooks)
    Console.WriteLine($"{pair.Key} -> {pair.Value}");

books.json faylında nə alınacaq?

{
  "Master i Margarita": "Mixail Bulgakov",
  "Garri Potter": "Joan Rowling",
  "Voyna i mir": "Vilyam Golding"
}

Necə işləyir?

Serializator bizim Dictionary<string, string>-i JSON-obyektinə çevirir: hər açar properti adına, dəyər isə həmin properti-nin qiymətinə çevrilir. Bu, açarlar string olduqda və unikal olduqda çox rahatdır.

3. Qeyri-standart açar tipli sözlük

Hər şey açar string olduğu zaman sadədir. Bəs açar ədəd olsa necə?


var bookIds = new Dictionary<int, string>
{
    [1001] = "Master i Margarita",
    [1002] = "Garri Potter",
    [1003] = "Povelitel mukh"
};

string jsonIntKeys = JsonSerializer.Serialize(bookIds, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(jsonIntKeys);

Nəticə:

{
  "1001": "Master i Margarita",
  "1002": "Garri Potter",
  "1003": "Povelitel mukh"
}

Nə baş verdi?

  • C# ədədi açarları string-ə çevirdi, çünki JSON-da property adları yalnız string ola bilər.
  • Deserializasiya zamanı isə serializator həmin stringləri yenidən ədədə çevirməyə çalışacaq.

Deserializasiya nümunəsi:


var restoredBookIds = JsonSerializer.Deserialize<Dictionary<int, string>>(jsonIntKeys);
// Hər şey işləyir! Açarlar yenidən ədədə çevrildi.
Açar mürəkkəb tipdirsə, məsələn obyekt?

var dict = new Dictionary<Author, string>
{
    [new Author { Name = "Golding", BirthYear = 1911 }] = "Povelitel mukh"
};

Belə bir sözlüyü serializasiya etməyə cəhd etsəniz, istisna ilə üzləşəcəksiniz:

System.NotSupportedException: Serialization and deserialization of 'Dictionary<Author, string>' instances are not supported.

Niyə belədir?

JSON-obyekti property adı kimi yalnız string qəbul edir. Ona görə də açarlar serializasiya zamanı string-ə aydın şəkildə çevrilə bilən sadə tiplər olmalıdır (çox vaxt string və ya ədəd). Mürəkkəb obyektləri standart vasitələrlə JSON-a açar kimi istifadə etmək mümkün deyil.

4. Dəyər kimi daxil olan obyektlərə malik sözlük

Açarlar ilə bitirdik — indi dəyər kimi mürəkkəb obyekt (məsələn, Book və ya Author) olduqda nə baş verir, baxaq.

Nümunə


public class Author
{
    public string Name { get; set; }
    public int BirthYear { get; set; }
}

var authorDirectory = new Dictionary<string, Author>
{
    ["bulgakov"] = new Author { Name = "Mixail Bulgakov", BirthYear = 1891 },
    ["golding"] = new Author { Name = "Vilyam Golding", BirthYear = 1911 }
};

string jsonAuthors = JsonSerializer.Serialize(authorDirectory, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(jsonAuthors);

Nəticə:

{
  "bulgakov": {
    "Name": "Mixail Bulgakov",
    "BirthYear": 1891
  },
  "golding": {
    "Name": "Vilyam Golding",
    "BirthYear": 1911
  }
}
  • Daxil olan obyektlər öz strukturlarına uyğun olaraq serializasiya olunur.
  • Dictionary<string, Author>-ə geri deserializasiya da problemsiz işləyir.

5. Sözlük başqa obyektin tərkibində

Çox vaxt sözlüklər daha böyük obyektin sahəsi kimi istifadə olunur. Məsələn, kitabxananın kataloqu var, hər açar janr adı, dəyər isə həmin janra aid kitablar siyahısıdır.


public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
}

public class Library
{
    public Dictionary<string, List<Book>> CatalogByGenre { get; set; }
}

var library = new Library
{
    CatalogByGenre = new Dictionary<string, List<Book>>
    {
        ["Fantastika"] = new List<Book>
        {
            new Book { Title = "Solaris", Author = "Stanislav Lem" }
        },
        ["Klassika"] = new List<Book>
        {
            new Book { Title = "Povelitel mukh", Author = "Vilyam Golding" },
            new Book { Title = "Zrimaya tma", Author = "Vilyam Golding" }
        }
    }
};

string jsonLibrary = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(jsonLibrary);

Çıxış JSON-dan fraqment:

{
  "CatalogByGenre": {
    "Fantastika": [
      {
        "Title": "Solaris",
        "Author": "Stanislav Lem"
      }
    ],
    "Klassika": [
      {
        "Title": "Povelitel mukh",
        "Author": "Vilyam Golding"
      },
      {
        "Title": "Zrimaya tma",
        "Author": "Vilyam Golding"
      }
    ]
  }
}

Hər şey işləyir — daxil olan sözlüklər və kolleksiyalar rekursiv şəkildə serializasiya və deserializasiya olunur.

6. Sözlüklərin serializasiyasının xüsusiyyətləri və "gizli tələlər"

Təkrarlanan açarlar

Sözlükdə açarlar həmişə unikal olur. Amma əgər əl ilə eyni açarla təkrarlanan JSON göndərsəniz:

{
  "foo": "first",
  "foo": "second"
}

Nəticə: sonuncu dəyər ("second") əvvəlkinin üzərinə yazılacaq, xəta olmayacaq. Çox JSON-parserlər belə davranır.

Elementlərin sırası

Sözlük — sırasız kolleksiyadır. Serializasiya zamanı JSON-da açarların sırası orijinaldan fərqlənə bilər. Əgər sıra vacibdirsə — açar-dəyər cütləri siyahısından istifadə edin (List<KeyValuePair<string, T>>), amma adətən sözlükdə sıra vacib olmur.

JSON və daxil olan sözlüklər

Daxilolma səviyyələri məhdudlaşdırılmayıb, amma hər səviyyə JSON məhdudiyyətlərinə uyğun olmalıdır (açarlar string, dəyərlər isə düzgün JSON-obyektlər/massivlər).

JsonSerializerOptions-dan istifadə

Bəzən property adlarının PascalCase deyil, camelCase olmasını istəyirsən. Bu frontend-də JavaScript ilə inteqrasiya edəndə önəmlidir, çünki orada camelCase sahə adları standart sayılır.


var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};

string camelJson = JsonSerializer.Serialize(authorDirectory, options);

Vacib: sözlüklərdə bu parametr yalnız daxil olan obyektlərin (onların property-lərinin) serializasiyasına təsir edir, sözlük açarlarına yox. Sözlük açarları həmişə C#-da göstərilən string kimi serializasiya olunur.

7. Mürəkkəb və qeyri-sətir açarlarla bağlı problemlər

String və ədədi açarlı sözlüklərin serializasiyası (məsələn, int, long, Guid) "qutudan çıxan kimi" işləyir. Amma istifadəçi tərtib etdiyi class və ya struct açar kimi istifadə edilərsə — NotSupportedException ilə qarşılaşacaqsınız.

Belə halları serializasiya etmək üçün bir neçə yanaşma var:

  • Sözlüyü başqa formatda saxlamaq — məsələn, sözlüyü "Key""Value" sahələri olan obyektlər massivinə çevirib serializasiya etmək.
  • Öz konverterinizi yazmaq (JsonConverter), hansı ki mürəkkəb açarı string-ə və geriyə çevirəcək.
  • Əgər struktur həqiqətən mürəkkəbdirsə — arxitekturaya yenidən baxın və mürəkkəb obyektləri sözlük açarı kimi istifadə etməmək daha məntiqli ola bilər.

Cütlər siyahısı kimi serializasiya etmə nümunəsi


public class AuthorInfo
{
    public Author Author { get; set; }
    public string Book { get; set; }
}
// Dictionary<Author, string> yerinə
var list = new List<AuthorInfo>
{
    new AuthorInfo { Author = new Author { Name = "Vilyam Golding", BirthYear = 1911 }, Book = "Povelitel mukh" }
};
// belə bir siyahı problemsiz serializasiya olunur

Müqayisə: serializasiya zamanı sözlük vs. cütlər siyahısı

Kolleksiya tipi JSON-struktur Nə vaxt istifadə etmək
Dictionary<string, Book>
{ "key1": {...}, "key2": {...} }
Açarlar sadə stringlərdirsə, sürətli axtarış və unikalıq lazım olduqda
List<KeyValuePair<string, Book>>
[{"Key": "key1", "Value": {...}}, ... ]
Açar mürəkkəb tipdirsə, sıranı saxlamaq və ya duplikatlara icazə vermək lazım olduqda

8. Müsahibə sualları üçün tipik məsələlər

1. Dictionary<DateTime, string> serializasiya etmək olarmı?
Bəli, amma açarlar string reprezentasiyasına çevrilir (adətən ISO formatında, məsələn "yyyy-MM-ddTHH:mm:ss"). Deserializasiya zamanı lokal və tarix formatlarından asılı olaraq problemlər yarana bilər.

2. Dictionary<int, string> serializasiya etsək nə baş verəcək?
Açarlar string kimi serializasiya olunacaq, baxmayaraq ki orijinal sözlükdə ədədlər olub. Geri deserializasiya normal işləyir.

3. Niyə obyekt açarlı sözlük serializasiya etmək olmaz?
Çünki JSON-obyektinin property adı yalnız string ola bilər, obyekt isə property adı ola bilməz.

4. Kompleks açarlı sözlük serializasiya etmək istəyirsinizsə nə etmək lazımdır?
Strukturunu yenidən nəzərdən keçirmək və ya sözlüyü "key-value" cütləri siyahısı kimi serializasiya etmək daha məntiqlidir — beləliklə açar tam obyekt kimi serializasiya olunur, property adı kimi yox.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Sadə lüğətin seriyalaşdırılması və deserializasiya edilməsi
Sadə lüğətin seriyalaşdırılması və deserializasiya edilməsi
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION