1. Giriş
Təsəvvür edin: siz Person sinfini yazmısınız, obyektin serializasiyasını fayla apardınız, bir neçə ay sonra isə qərar verdiniz ki, ona yeni yaşayış ünvanı lazımdır və ya bəzi xassələrin tipini dəyişdiniz. Görünən odur ki, adi işdir — amma əvvəlki formatda saxlanmış məlumatları yükləməyə (deserializasiya etməyə) çalışdıqda sürpriz gözləyə bilər: nəsə yüklənməyə bilər, istisna atıla bilər, bəzi dəyərlər boş və ya səhv ola bilər.
Belə davranış — geri uyğunluğun pozulmasının tipik nümunəsidir. Real inkişafda bu, tələbələrin nöqtə-vergül qoymağı unutmasından daha tez-tez baş verir (yəni çox tez-tez).
Məsələni nümunə vasitəsilə təsəvvür edək
Tədris mini-proyektimizi götürək. Tutaq ki, indiyə qədər bizim sinif belə idi:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Bu sinif nümunəsini JSON-a serializə edək:
Person p = new Person { Name = "Alice", Age = 35 };
string json = JsonSerializer.Serialize(p);
File.WriteAllText("person.json", json);
Faylda belə alındı:
{"Name":"Alice","Age":35}
İndi, bir həftə sonra, tətbiqimizi bir az modernləşdirmək üçün ünvan sahəsi əlavə etməyə qərar verək:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; } // yeni sahə
}
Sonra köhnə faylı yükləməyə çalışaq:
string json = File.ReadAllText("person.json");
Person p = JsonSerializer.Deserialize<Person>(json);
Nə baş verəcək? Obyektimizdə Address (ünvan) olmayacaq: Address xassəsi null olacaq. Heç bir səhv yaranmadı. Hər şey hələ işləyir... Amma tipləri dəyişməyə, sahələri silməyə və ya həqiqətən "maraqlı" işlər görməyə başlayanda problemlər başlaya bilər!
2. Dəyişiklik növləri və onların təsiri
Sinif strukturundakı dəyişikliklər serializasiya üzərində müxtəlif cür təsir edir. Bir neçə tipik ssenarini nəzərdən keçirək.
Yeni xassələrin əlavə edilməsi
Bu ən təhlükəsiz variantdır. Köhnə məlumatlar (orada bu xassələr yox idisə) rahat şəkildə deserializasiya olunur: yeni xassələr defolt dəyərlərə bərabər olur (null referanslar üçün, 0 üçün int və s.).
Diqqət: Əgər yeni xassəniz nullable deyil və "məntiqli" defolt dəyəri yoxdursa, problem ola bilər (xüsusən C# 11+ ilə required-xassələrdə).
Xassələrin silinməsi
Əgər siz xassəni sildirirsinizsə, amma serializə edilmiş məlumatlarda o hələ də varsa — serializator çox güman ki, həmin "artıq" sahəni sadəcə gözardı edəcək və yükləmə yenə baş tutacaq.
Amma bu istifadə etdiyiniz serializatora bağlıdır. Məsələn, JsonSerializer və Newtonsoft.Json kifayət qədər tolerantdır: onlar istisna atmayacaqlar, amma bəzi köhnə və ya custom serializatorlar fərqli davranış göstərə bilər.
Xassələrin yenidən adlandırılması
Burada əyləncə başlayır. Əgər siz sadəcə FirstName-i Name-ə dəyişsəniz, serializator köhnə məlumatlardakı sahələrlə yeni obyekt arasında uyğunluq qura bilməyəcək. Yəni sahə boş olacaq (null/0), fayldakı köhnə dəyər isə gözardı ediləcək.
Xassənin tipinin dəyişdirilməsi
Məsələn, əvvəllər sizin public int Age var idi, sonra onu public string Age-ə çevirdiniz (birdən kimsə "bessmertny" daxil edər — hər şey ola bilər). Köhnə məlumatları deserializasiya etməyə çalışmaq səhvə gətirə bilər ("Cannot convert number to string") və ya xassə sadəcə defolt dəyər alacaq. Hər şey konkret serializatora və onun tip yoxlaması parametrlərinə bağlıdır.
İyerarxiyaların dəyişməsi (miras, nested strukturlar)
Əgər siz baza siniflərini dəyişirsinizsə, xassələri başqa yerlərə keçirirsinizsə və ya bir sinfi başqa bir sinifin əhatəsinə alırsınızsa — köhnə serializə edilmiş məlumatlar tamamilə uyğunsuz ola bilər. Bu xüsusilə XML və kompleks obyekt iyerarxiyaları üçün doğrudur.
3. Uyğunluq problemləri
Uyğunluq problemlərini necə aşkar etmək olar?
Uyğunluq xətası çox vaxt dərhal və açıq görünmür: tətbiqiniz sadəcə " qəribə " davranmağa başlayır, bəzi məlumatlar itir, və ya loglarda elə də məlumatlı olmayan istisna görünür. Ən çox problemlər aşağıdakı halda üzə çıxır:
- İstifadəçi köhnə faylı yeni versiyaya yükləyir.
- Server klientin "köhnə versiya" JSON/XML göndərdiyini alır.
- Xarici API ilə işləyərkən onun interfeysi birdən yenilənir.
Simptomlar müxtəlif olur: deserializasiya xətalarından tutmuş "gözlənilmədən" boş sahələrə qədər.
Serializatorun uyğunluğa təsiri
Bütün serializatorlar eyni cür davranmır. JSON-serializatorlar — həm standard System.Text.Json, həm də Newtonsoft.Json — struktur dəyişikliyinə qarşı nisbətən tolerantdır. Onlar fayldakı naməlum xassələri keçib gedir, obyektin naməlum sahələrini isə serializə etmirlər.
XML-də hər şey bir az daha ciddi ola bilər: əgər root elementi və ya iyerarxiya dəyişərsə, xətalar baş verə bilər.
Ikili formatlarda isə sıralama və tiplər dəyişibsə, istisnalar mümkün ola bilər!
4. Riskləri necə minimallaşdırmaq olar? Yanaşmalar və praktikalar
Bir neçə yanaşma var ki, mümkün problemləri minimuma endirməyə kömək edər (bəzən tamamilə aradan qaldırar).
Siniflərin və məlumatların versiyasından istifadə edin
Serializə olunan obyektlərə və ya fayla xüsusi Version sahəsi əlavə edin. Bu faylın hansı struktur versiyası ilə yaradıldığını müəyyən etməyə və yükləmə zamanı uyğun qərar verməyə (məsələn, məlumatları upgreyd etmək) imkan verəcək.
public class PersonV2
{
public int Version { get; set; } = 2;
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
Adların xəritələnməsi atributlarından istifadə edin (serializasiya üçün)
JSON və XML üçün sahənin serializə edilmiş formada necə adlandırılacağını açıq göstərmək olar. Əgər sahəni yenidən adlandırırsınızsa — köhnə adı saxlayın:
public class Person
{
[JsonPropertyName("FirstName")] // System.Text.Json üçün
[JsonProperty("FirstName")] // Newtonsoft.Json üçün
public string Name { get; set; }
public int Age { get; set; }
}
Nullable tiplərdən və defolt dəyərlərdən istifadə edin
Yeni sahələriniz köhnə məlumatlarda olmayacaqsa — onları nullable edin və ya məntiqli defolt dəyər təyin edin ki, deserializasiya problem çıxarmasın:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string? Address { get; set; } = "Unknown";
}
"Naməlum sahə" hadisələrinin emalı
Newtonsoft.Json-də "anlaşılmayan" sahələri xüsusi handler vasitəsilə ələ ala bilərsiniz, məsələn, potensial təhlükəli situasiyanı loglamaq üçün.
var settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error
};
try
{
var person = JsonConvert.DeserializeObject<Person>(json, settings);
}
catch (JsonSerializationException ex)
{
Console.WriteLine("Deserializasiya alınmadı: " + ex.Message);
}
Məlumatların miqrasiyası
Əgər dəyişikliklər əhəmiyyətlidirsə, miqrasiya mərhələsi nəzərə alınmalıdır: məsələn, məlumatları əvvəl "köhnə" strukturda yükləyib sonra yeni struktura çevirmək:
// Tutaq ki, PersonV1 ünvan olmadan idi
public class PersonV1 { public string Name; public int Age; }
// Yeni — ünvan ilə
public class PersonV2 { public string Name; public int Age; public string Address; }
// Miqrasiya:
string oldJson = File.ReadAllText("person.json");
PersonV1 oldPerson = JsonSerializer.Deserialize<PersonV1>(oldJson);
PersonV2 migrated = new PersonV2
{
Name = oldPerson.Name,
Age = oldPerson.Age,
Address = "Unknown"
};
5. Çətin hallar və gözlənilməz xətalar
Field invariantlığı və required-xassələr
C# 11 və daha yenilərində required-xassələr peyda oldu. İndi əgər sahə required kimi işarələnibsə, deserializasiya həmin sahə məlumatda yoxdursa, xətaya səbəb ola bilər:
public class Person
{
public string Name { get; set; }
[JsonPropertyName("Age")]
public required int Age { get; set; }
public string Address { get; set; }
}
Əgər köhnə məlumatlarda Age sahəsi yoxdursa — struktur uyğunsuzluğu barədə istisna olacaq.
Tipin dəyişməsi: int → string
// Əvvəl:
public class Record { public int Count; }
// İndi:
public class Record { public string Count; }
Əgər məlumatda "Count":42 varsa, deserializasiya string-ə işləyə bilər (smart-konvertasiya), amma əksinə — exception ola bilər.
Baza sinfinin silinməsi
Əgər serializə edilmiş obyekt miras alıbsa və iyerarxiyanı dəyişdirmisinizsə — köhnə faylları deserializasiya edərkən səhvlər baş verə bilər, bəzən sakit, bəzən açıq şəkildə.
6. Uyğunluqla işləyərkən tipik səhvlər
Səhv №1: mövcud xassələri düşüncəsizcə dəyişmək.
Xassələrin adını dəyişmək və ya tipini dəyişmək, mövcud serializə edilmiş məlumatları nəzərə almadan, deserializasiya zamanı məlumat itirməsinə gətirir.
Səhv №2: yeni sahələr üçün nullable tipləri unutmaq.
Yeni xassələr ya nullable olmalı, ya da məntiqli defolt dəyəri olmalıdır.
Səhv №3: geri uyğunluğu test etməmək.
Sinifi dəyişdiniz — mütləq yoxlayın ki, köhnə fayllar/məlumatlar hələ də düzgün yüklənir.
Səhv №4: müxtəlif kitabxanaların atributlarını qarışdırmaq.
Bir xassədə eyni anda JsonPropertyName və JsonProperty-dən istifadə etməyin.
GO TO FULL VERSION