1. Dəyişməzlik nədir?
Gəlin analoji ilə başlayaq: təsəvvür et ki, sən hər gün satış hesabatı hazırlayan bir mühasibsən. Həqiqi peşəkar kimi, keçən həftənin hesabatını dəyişmirsən, sadəcə yenisini yaradırsan — köhnənin əsasında, amma yenilənmiş məlumatlarla. Proqramlaşdırmada dəyişməz obyektlər də eynidir: belə obyekt yaradıldıqdan sonra dəyişmir, istənilən "dəyişiklik" isə yeni bir kopyanın yaradılması deməkdir.
Dəyişməzlik (immutability) — obyektin ilkinizasiya olunduqdan sonra dəyişməməsi xüsusiyyətidir. Onun bütün xüsusiyyətləri "dondurulur": başqa dəyər istəyirsənsə — yeni obyekt yarat.
Bunun nə faydası var?
- Təhlükəsizliyi təmin edir: əgər obyektini heç kim təsadüfən dəyişə bilmirsə, məlumatların birdən-birə pozulmaz. Bu, çox vaxt multithread proqramlarda olur, bir neçə thread eyni anda nəsə dəyişməyə çalışanda.
- Debug-u asanlaşdırır: obyekt dəyişmirsə, onun yaradılmasından sonra nə baş verdiyini dəqiq bilirsən.
- Məlumat ötürmək üçün rahatdır, xüsusilə paylanmış sistemlərdə, harada ki, kopyalar fərqli ola bilər.
- "Vəziyyət snapshot-ları" (snapshots) yaratmağa imkan verir — dəyişikliklərin tarixi aydın olur.
2. record tiplərində dəyişməzlik
Adi class elan edəndə, xüsusiyyətləri default olaraq dəyişəndir (mutable). Nümunə:
public class UserProfile
{
public string Name { get; set; }
public int Age { get; set; }
}
var user = new UserProfile { Name = "İvan", Age = 25 };
user.Age = 26; // Hər şey ok — adi class: yaşı "uçan" dəyişirik
record üçün isə default vəziyyət fərqlidir: onlar dəyişməz məlumat saxlamaq üçündür.
public record UserProfile(string Name, int Age);
// Obyekt yaradırıq:
var user = new UserProfile("İvan", 25);
// Yaşı dəyişməyə çalışırıq:
user.Age = 26; // Kompilyasiya xətası: xüsusiyyət yalnız oxumaq üçündür!
Pozisional record xüsusiyyətləri yalnız oxumaq üçün (init-only) elan olunur. Onları yaradandan sonra dəyişə bilməzsən, amma with-ifadəsi ilə dəyişilmiş xüsusiyyətlərlə yeni kopya yarada bilərsən.
Dəyişən class-lar vs dəyişməz record-lar
| Class | Record-pozisional |
|---|---|
Default xüsusiyyətlər |
Dəyişməz |
| Necə dəyişmək olar Xüsusiyyətə müraciət |
Yalnız yeni kopya yaratmaqla |
| Obyektlərin müqayisəsi Referansla (ReferenceEquals) |
Dəyərlə (Equals) |
| Məlumat ötürmək üçün rahatdır Həmişə deyil |
Bəli |
3. with-ifadələri
Yəqin düşündün — "record superdi, bəs indi necə yaşayaq, əgər onları dəyişmək olmursa?" Bax burada with-ifadələrinin magiyası gəlir!
with — xüsusi sintaksisdir, hansı ki, yeni kopya record yaradır, sadəcə lazım olan xüsusiyyətləri dəyişir.
Yəni: "Bu obyekti götür, kopyasını yarat, amma burda bir neçə xüsusiyyəti dəyiş."
Ən sadə nümunə
var user1 = new UserProfile("Anna", 30);
// ... amma həyat yerində durmur, Anna böyüdü
var user2 = user1 with { Age = 31 };
// user1 eyni qaldı, user2 — kopya, amma bir yaş böyük
Console.WriteLine(user1); // UserProfile { Name = Anna, Age = 30 }
Console.WriteLine(user2); // UserProfile { Name = Anna, Age = 31 }
Qapağın altında
Bu mutant-klon deyil, yeni obyektdir, hansı ki, xüsusi avtomatik yaradılan Clone() metodu ilə yaradılır, kopya yaradır və yeni dəyərləri qoyur.
Əgər with-ifadələri həyatda olsaydı, səhərlər "köhnə yorğun bədəndə" yox, özünün kopyasında, yaxşı əhval və daha böyük əzələlərlə oyanardın (amma yalnız record olsaydın).
4. Bir az iç-içəlik və kopyalama haqqında
Əgər record başqa record saxlayırsa — hər şey qaydasındadır:
public record Address(string City, string Street);
public record Student(string Name, int Age, string Email, Address Home);
var a1 = new Address("Moskva", "Tverskaya");
var s1 = new Student("Lena", 21, "lena@mail.ru", a1);
var s2 = s1 with { Home = a1 with { Street = "Arbat" } };
Burada hər şey həqiqətən dəyişməz işləyəcək, çünki içindəki Address də record-dur.
5. Son nüanslar
Pozisional record = qısa sintaksis
Record-u “qısa” formada (pozisional sintaksis) elan etmək olar. Onda bütün xüsusiyyətlər avtomatik olaraq init-only olur.
public record Course(string Name, int Credits);
var c1 = new Course("C#", 5);
var c2 = c1 with { Credits = 6 };
Yalnız oxumaq üçün xüsusiyyətlərə (init-only) bənzərlik
Record-da xüsusiyyətləri belə də açıq elan etmək olar:
public record Student
{
public string Name { get; init; }
public int Age { get; init; }
}
Belə xüsusiyyətləri də yalnız ilkinizasiya zamanı (və ya with ilə) dəyişmək olar.
6. Praktika: demo-tətbiq
Gəlin öz tədris "Online-məktəb"imizi yazaq. Tutaq ki, artıq tələbə üçün record-umuz var:
public record Student(string Name, int Age, string Email);
Klassika: kimsə email-də səhv edib, amma tələbə artıq hesab yaradıb. "Email-i yeniləmək" necə olsun? Əlbəttə, with ilə!
var student = new Student("Ekaterina", 19, "kate@school.com");
var updatedStudent = student with { Email = "ekaterina@school.com" };
// Obyektləri yoxlayaq:
Console.WriteLine(student); // Student { Name = Ekaterina, Age = 19, Email = kate@school.com }
Console.WriteLine(updatedStudent); // Student { Name = Ekaterina, Age = 19, Email = ekaterina@school.com }
7. Tipik səhvlər və tələlər
İndi bir az ağrıdan danışaq — tələbələrin dəyişməz record-larla oynayanda ən çox səhv etdiyi yerlər.
- Birincisi, çoxları düşünür ki, with orijinal obyekti dəyişir. Əslində, orijinal obyekt eyni qalır, yeni isə dəyişilmiş sahələrlə yaradılır. Bəzən buna görə tələyə düşüb yeni dəyərləri itirirlər.
- İkincisi, yadında saxla: əgər record-un içində dəyişən obyektlər varsa (məsələn, massiv və ya List), with-ifadəsi dərin kopyalama etmir! Kolleksiyan hər iki kopya üçün eyni olacaq.
public record Student(string Name, int Age, List<string> Subjects);
var s1 = new Student("Oleg", 22, new List<string> { "Math", "Physics" });
var s2 = s1 with { };
s1.Subjects.Add("C#"); // Bax, indi s2.Subjects də "C#" daxildir
Bax buna görə truly immutable state üçün yalnız sadə tiplər və ya özü dəyişməz olan kolleksiyalardan (ImmutableList<T> və s. System.Collections.Immutabledən) istifadə etmək yaxşıdır.
Əgər həqiqi dəyişməzlik istəyirsənsə, bu kolleksiyalardan istifadə et və ya manual dərin kopyalama et.
GO TO FULL VERSION