1. Giriş
Pozision sintaksisi record-klass üçün sadə hallarda həqiqətən rahatdır:
public record User(string Name, int Age);
Amma bəzən səndə güclü istək yaranır ki, record-a əlavə metodlar, qeyri-standart property-lər əlavə edəsən, access modifier-ləri dəyişəsən, konstruktorun içinə məntiq (məsələn, validation və ya "avtomatik" data çevirmə) əlavə edəsən. Təəssüf ki, pozision yazıda bunları əlavə etməyə yer yoxdur! Artıq açıq bədən sintaksisinə keçmək vaxtıdır, əgər:
- Record-u metodlarla, property-lərlə və ya əlavə məntiq ilə genişləndirmək istəyirsən.
- Property-lərin davranışına nəzarət etmək lazımdır (setter, getter, init, validation və s.).
- Fərqli initializasiya yolları üçün bir neçə konstruktor yaratmaq lazımdır.
- İnterfeys əlavə etmək və ya xüsusi metodlar implementasiya etmək lazımdır.
record bədənlə qururuq
Sintaksis class-a çox bənzəyir. Bu forma sənə tanışdır:
public class User
{
/* ... */
}
Sadəcə indi bu record olacaq:
public record User
{
// Açıq təyin olunmuş property-lər
public string Name { get; init; }
public int Age { get; init; }
// Əlavə məntiq
public string GetGreeting()
{
return $"Salam, mənim adım {Name}-dır və mənim {Age} yaşım var!";
}
// Custom konstruktor
public User(string name, int age)
{
Name = name;
if (age < 0)
throw new ArgumentException("Age mənfi ola bilməz!");
Age = age;
}
}
Maraqlı fakt: Əgər property-ləri açıq təyin edirsənsə, compiler pozision sintaksisdən avtomatik property yaratmır. Hər şey açıq, hər şey sənin nəzarətindədir.
Qarışıq variant: hibrid sintaksis
C# hər iki dünyanı birləşdirməyə imkan verir: sən pozision record elan edə bilərsən və ona bədən əlavə edə bilərsən:
public record User(string Name, int Age)
{
public string GetGreeting()
{
return $"Mən {Name}-am, mənim {Age} yaşım var!";
}
}
Bu halda Name və Age property-ləri yenə də pozision sintaksis ilə avtomatik yaradılır, sənin əlavə metodların isə rahatlıqla bədənin içində yerləşir.
2. Adi record-lardan fərqlər — bədən nüansları
- Açıq record konstruktorlara, property-lərə, metodlara tam nəzarət etməyə imkan verir.
- İnterfeys implementasiya edə bilərsən və ya obyektin identifikasiyası üçün xüsusi müqayisə məntiqi əlavə edə bilərsən.
- Sadə pozision record-dan fərqli olaraq, yeni property əlavə etmək üçün sadəcə bədənin içində onları elan etmək kifayətdir.
// Yeni başlayanların səhvi!
public record User(string Name, int Age)
{
public string Name { get; init; } // ← konflikt! Property-nin təkrar elan olunması
}
Yeni başlayanların səhvləri: Bəzi tələbələr eyni anda public record User(string Name, int Age) yazıb, bədənin içində də public string Name { get; init; } property-si əlavə edirlər, elə bilirlər ki, bunlar iki fərqli dəyişəndir. Xeyr! Bu konflikt olacaq (təkrar elan). Ya tam pozision sintaksis istifadə et, ya da property-ləri açıq elan et — qarışdırma.
Praktiki nümunələr
Konsol tətbiqi hazırlamağa davam edirik, burada istifadəçi sifarişlər yaradır. Tutaq ki, sifariş üçün Order adlı class var idi, o belə görünürdü:
public record Order(string Product, int Quantity, double Price);
Tutaq ki, indi bizə quantity üçün validation lazımdır (quantity 1-dən az ola bilməz) və əlavə ümumi məbləğ property-si:
public record Order
{
public string Product { get; init; }
public int Quantity { get; init; }
public double Price { get; init; }
public double TotalCost => Quantity * Price;
public Order(string product, int quantity, double price)
{
Product = product ?? throw new ArgumentNullException(nameof(product));
if (quantity < 1)
throw new ArgumentException("Say 1-dən az ola bilməz!");
Quantity = quantity;
Price = price;
}
public override string ToString()
=> $"Məhsul: {Product}, Say: {Quantity}, Cəmi: {TotalCost}";
}
Qeyd et ki, property-ləri açıq elan etdik, onları init-setter ilə etdik (dəyişməz obyektlər), avtomatik məbləğ hesablanması əlavə etdik — kod daha çevik oldu!
Proqramda çağırış:
var order = new Order("Velosiped", 2, 15000);
Console.WriteLine(order); // Məhsul: Velosiped, Say: 2, Cəmi: 30000
3. record struct
struct-ların təkamülü
record struct gəlməmişdən əvvəl C#-da struct-lar "sadə işçi atlar" idi — tez kopyalanan, stack-də saxlanılan, qısa “Parcel” datalar üçün (məsələn, koordinatlar və ya rənglər) əla idi. Amma onlar records-un bütün üstünlüklərini dəstəkləmirdi: pozision sintaksis yox idi, with-ifadələri yox idi, default olaraq value ilə müqayisə və digər “şirin şeylər” yox idi.
İndi C#-da struct-ları record stilində elan etmək olar:
public record struct Point(int X, int Y);
Bəs bu bizə nə verir?
- Avtomatik Equals, GetHashCode, ToString implementasiyası — indi sənin struct-un gözəl müqayisə və çap edə bilir!
- with-klonlama sintaksisi: var p2 = p1 with { X = 10 };
- Pozision və ya açıq sintaksis istifadə etmək imkanı.
Müqayisə: klassik struct VS record struct
| struct | record struct | |
|---|---|---|
| Pozision sintaksis | Yox | Bəli |
| with-ifadə | Yox | Bəli |
| Dəyişməzlik | Yox (default) | Bəli (init) |
| Value ilə müqayisə | Yox (default) | Bəli |
| ToString | Standart | Gözəl |
record struct üçün açıq bədən sintaksisi
Hər şey adi record kimi, sadəcə struct:
public record struct Rectangle
{
public int Width { get; init; }
public int Height { get; init; }
public int Area => Width * Height;
public Rectangle(int width, int height)
{
Width = width > 0 ? width : throw new ArgumentException("En > 0");
Height = height > 0 ? height : throw new ArgumentException("Hündürlük > 0");
}
public void Print()
{
Console.WriteLine($"Ölçülər: {Width} x {Height}, sahə: {Area}");
}
}
İstifadə nümunəsi:
var rect = new Rectangle(10, 7);
rect.Print(); // Ölçülər: 10 x 7, sahə: 70
// Klonlayırıq və eni dəyişirik, orijinal dəyişmir
var wideRect = rect with { Width = 20 };
wideRect.Print(); // Ölçülər: 20 x 7, sahə: 140
record struct xüsusiyyətləri
- Bu hələ də struct-dır — value type. Təyinatda kopyalanır!
- Records-un bütün üstünlükləri: value ilə müqayisə, with-klonlama, gözəl ToString.
- Kiçik, kompakt, dəyişməz data set-ləri üçün tövsiyə olunur, burada heap-də allocation-dan qaçmaq vacibdir.
- Pozision parametrlər elan edə və ya açıq “bədən” yaza bilərsən.
4. Tipik səhvlər və tələlər
Həddindən artıq mutabillik: record struct sahələri avtomatik dəyişməz etmir, əgər onları adi kimi elan edirsənsə (məsələn, public int Value;). Həqiqətən immutable struct üçün init-setter istifadə et!
Müqayisə: Əgər yeni sahələri əl ilə əlavə edirsənsə (pozision sintaksisə daxil etməmisənsə), bil ki: yalnız konstruktor və ya init-setter ilə olan sahələr avtomatik value müqayisəsində iştirak edir.
Kopyalama: Bu struct-dır, yəni... hər şey kopyalanır! Record class-larla qarışdırma.
with-ifadələrlə qarışıqlıq: Onlar həmişə shallow copy yaradır, yəni iç-içə obyektlər üçün dərin kopyalama etmir.
GO TO FULL VERSION