1. Giriş
Biz artıq proqramlarımızda obyektlər yaratmağa alışmışıq. Yaddaqalan odur ki, biz dərslərdə tezliklə class və obyektləri daha dərindən öyrənəcəyik, amma artıq indi başa düşürük ki, dəyişənlər, siyahılar, hətta sadə sətrlər — sadəcə dəyərlər deyil, proqramımızda müəyyən "məhvər"lərdir. Məsələn, biz bir dəyişən yarada bilərik int age = 30; və ya string name = "Vasya";. Amma əgər bizə istifadəçinin adı, yaşı, ünvanı, sevimli kitablar siyahısı və daha çoxunu fayla saxlamaq lazım olsa necə?
Təsəvvür edin: siz oyun yazırsınız. Sizin Player obyekti var, bir ton xüsusiyyətlərlə: health, level, inventory (obyektlərin siyahısı), koordinatlar və s. Oyunçu oynayır, level atlayır, əla artefaktlar tapır. Və birdən çıxmaq qərarına gəlir. Nə olur? Onun macəraları haqqında yaddaşda saxlanılan bütün məlumatlar itir — təəssüf! Bunun qarşısını almaq üçün bizə lazımdır ki, Player obyektinin vəziyyətini fayla saxlayaq və oyunçu geri qayıdanda onu yenidən yükləyək.
Burada səhnəyə serialization çıxır. O məhz "canlı" yaddaşdakı obyektlərlə diskdə saxlanılan "ölü" amma davamlı verilər arasında körpü yaradır.
2. Serialization prosesi (obyektdən fayla)
Gəlin obyektin baytlara çevrilməsi və fayla yazılması "sehrini" addım-addım araşdıraq.
Tutaq ki, aşağıdakı kimi bir klassımız var — Book (Kitab):
// Bu bizim "plan"ımız və ya "şablon"umuzdur, Book obyektləri yaratmaq üçün
public class Book
{
// Kitabın xassələri
public string Title { get; set; } // Kitabın adı
public string Author { get; set; } // Müəllif
public int Year { get; set; } // Nəşr ili
// Constructor - yeni Book obyektləri yaratmaq üçün xüsusi metod
public Book(string title, string author, int year)
{
Title = title;
Author = author;
Year = year;
}
// Kitab haqqında məlumatı rahat çap etmək üçün metod (hal-hazırda serialization üçün məcburi deyil, amma faydalıdır)
public void DisplayInfo()
{
Console.WriteLine($"Ad: {Title}, Müəllif: {Author}, İl: {Year}");
}
}
1-ci addım: serialization üçün obyekt yaratmaq.
Əvvəlcə əlbəttə ki, saxlamaq istədiyimiz obyekt lazımdır. Məsələn, Book nümunəsi yaratdıq:
Book myFavoriteBook = new Book("Avtostopom po Galaktike", "Duglas Adams", 1979);
Bu obyekt myFavoriteBook indi RAM-da yerləşir.
2-ci addım: alətin (serializer-in) seçilməsi.
Biz obyektin özü birbaşa fayla "köçürə" bilmərik. Kompüter faylda obyektləri birbaşa anlamır — ona baytlar lazımdır. Xüsusi alət — serializer lazımdır. Onun işi bizim obyekti onun hissələrinə (xassələrinə: Title, Author, Year) parçalamaq və bu hissələri bayt ardıcıllığına və ya mətnə (məsələn JSON və ya XML) çevirməkdir.
Bu dərsdə konkret implementasiyalara dərindən girmirik — sadəcə ağlınızda saxlayın ki, bu xüsusi "çevirmə qutusu"dur.
3-cü addım: obyekti məlumat axınına çevirmək.
Serializer bizim myFavoriteBook obyektini götürür, onun xassələrinə baxır (Title, Author, Year) və hər birini yazıla bilən formata çevirir. Bu baytlar (və ya mətn simvolları) birləşdirilib vahid məlumat axını — uzun bir "lent" əmələ gətirir.
4-cü addım: axını fayla yazmaq.
Bu "bayt lenti" hazır olduqda, biz tanış FileStream və ehtiyac olduqda StreamWriter (əgər mətn formatı seçilibsə, məsələn JSON) və ya sadəcə FileStream (təmiz binar üçün) vasitəsilə bu axını diskə yazırıq.
3. Deserialization prosesi (fayldan obyektə)
1-ci addım: fayldan məlumat axınını oxumaq.
Biz yenə FileStream və lazım olsa StreamReader (mətn formatıdırsa) istifadə edərək faylın məzmununu oxuyuruq. Məlumatlar bayt və ya mətn "lenti" kimi gəlir.
2-ci addım: alətin (deserializer-in) seçilməsi.
Əks alət — deserializer lazımdır. O, alınan baytları/mətnləri necə interpretasiya edəcəyini bilməlidir və düzgün şəkildə obyekt strukturunu yenidən yaratmalıdır. Vacibdir: deserialization üçün adətən eyni serializer tipi (və eyni kitabxana) istifadə olunur; əks halda "yığın" (constructor) təlimatları anlamaya bilər.
3-cü addım: axını yenidən obyektə çevirmək.
Deserializer məlumatları oxuyur, harada Title olduğunu, sonra Author-ı, sonra Year-ı anlayır və bu əsasında yaddaşda yeni Book obyekti yaradıb xassələrini doldurur.
4-cü addım: hazır obyektin alınması.
Voila! Yenə tam funksional Book obyektimiz var və onunla işləyə bilərik.
Nümunə: "Super-Kitab"ımızı əl ilə saxlayırıq (konsepti anlamaq üçün)
İndi xüsusi kitabxanalardan istifadə etməyəcəyik: StreamWriter və StreamReader ilə ən sadə "əl ilə" serialization və deserialization edək. Bu prinsipi anlamağa kömək edəcək.
Bizim Book obyektimiz:
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public int Year { get; set; }
public Book(string title, string author, int year)
{
Title = title;
Author = author;
Year = year;
}
public void DisplayInfo()
{
Console.WriteLine($"Ad: \"{Title}\", Müəllif: {Author}, İl: {Year}");
}
}
Əl ilə serialization: SaveBookToTextFile metodu
Kitabın xassələrini bir-bir sətirə yazacaq bir metod yaradaq.
void SaveBookToTextFile(Book book, string filePath)
{
using var writer = new StreamWriter(filePath);
writer.WriteLine(book.Title);
writer.WriteLine(book.Author);
writer.WriteLine(book.Year);
}
Nə baş verir? StreamWriter açırıq və ardıcıl olaraq Title, Author, Year yazırıq — bu bizim ən sadə serialization sxemimizdir.
Əgər kodu işə salsaq, faylın məzmunu belə olacaq:
Avtostopom po Galaktike
Duglas Adams
1979
Əl ilə deserialization: LoadBookFromTextFile metodu
İndi məlumatı oxuyub yeni Book obyekti toplayacaq metodu yazaq.
Book LoadBookFromTextFile(string filePath)
{
using var reader = new StreamReader(filePath);
string title = reader.ReadLine();
string author = reader.ReadLine();
int year = int.Parse(reader.ReadLine());
return new Book(title, author, year);
}
Və bu metodları Main-də belə istifadə edirik:
//obyekti yaradırıq
var myBook = new Book("Avtostopom po Galaktike", "Duglas Adams", 1979);
string filePath = "my_favorite_book.txt";
//onu fayla saxlayırıq
SaveBookToTextFile(myBook, filePath);
//fayldan oxuyuruq
Book loadedBook = LoadBookFromTextFile(filePath);
LoadBookFromTextFile-da nə baş verir? StreamReader açırıq və eyni ardıcıllıqla sətirləri oxuyuruq: əvvəl title, sonra author, sonra year və onu int.Parse vasitəsilə int-ə çeviririk. Sonra yeni Book nümunəsi yaradırıq.
Amalda File.Exists yoxlamaları və try-catch ilə səhv idarəsi əlavə etmək lazımdır, amma burada əsas ideyaya fokuslanırıq.
Niyə "əl ilə" serialization pisdir (və niyə kitabxanalar lazımdır)?
- Çox əl işi lazımdır. Hər xassəni ayrıca yazıb sonra oxumalısınız. Əgər obyektlər və sahələr çoxdursa — kod böyüyür.
- Dəyişikliklərə həssasdır. Yeni xassə əlavə etdinizsə, məsələn Pages (int)? Yazma və oxuma kodunu dəyişmək lazım gələcək və ardıcıllığa ciddi nəzarət tələb olunur.
- Mürəkkəb strukturlar. İç-içə kolleksiyalar və obyektlər (məsələn, List<Chapter>) kodun "spagetti"yə çevrilməsinə səbəb olar.
- Formatlar və effektivlik. Mətn formatı sadədir, amma həmişə kompakt və təhlükəsiz deyil; binar verilərlə işləmək üçün əl ilə baytlarla, BinaryWriter/BinaryReader və s. işləmək lazım gəlir.
- Metadataların yoxluğu. Fayl "bilməz" ki, birinci sətir Title, üçüncü sətir isə Year-dir. Spesifik serializer-lər metadataları saxlayıb modellərin dəyişmələrinə daha dayanıqlı ola bilərlər.
Məhz buna görə real layihələrdə hazır serializer kitabxanaları istifadə olunur — onlar obyektləri avtomatik parçalayır/yığır, JSON, XML və binar formatlarla işləyir və modellərin dəyişmələrini daha möhkəm idarə edirlər. Bu mövzu növbəti mühazirədə olacaq!
Praktik tətbiq: serialization nəyə lazımdır?
- Məlumatın saxlanması və yüklənməsi. Parametrlər, oyun vəziyyəti, konfiqurasiyalar.
- Şəbəkə üzərindən məlumat ötürülməsi. Xidmətlər arasında mürəkkəb obyektlərin mübadiləsi (çox vaxt JSON-da).
- Keşləmə (caching). Əvvəlcə alınmış məlumatların tez yenidən istifadə edilməsi.
- Mürəkkəb obyektlərin loglanması. Debug və audit üçün rahatdır.
- Obyektlərin dərin klonlanması. Serialization + deserialization obyekt qrafının klonlanması üçün üsuldur.
Serialization müasir proqram təminatının əsas sütunlarından biridir: oyunlarda progressin saxlanmasından tutmuş web-servislərlə işləməyə qədər — hər yerdədir!
GO TO FULL VERSION