1. Giriş
Əvvəllər class-lara yalnız Extension-metodlar əlavə etmək olurdu. Amma property (property) kimi class-a extension əlavə etmək mümkün deyildi! Yəni, əgər istəyirdin ki, hər hansı DateTime-da IsWeekend property-si olsun, bunu ancaq metodla etmək olurdu, bu isə həmişə rahat olmur — xüsusilə də date.IsWeekend sintaksisi istəyəndə, date.IsWeekend() əvəzinə.
C# 14 çıxandan sonra arzu reallaşdı: indi extension property-ləri metodlara bənzər şəkildə yaza bilərsən. Onlar mövcud tipə yeni property əlavə etməyə imkan verir, kodun özünü dəyişmədən və onları adi property kimi istifadə edə bilərsən!
Harada həqiqətən faydalıdır?
- Standart .NET tipləri və dəyişə bilmədiyin üçüncü tərəf kitabxanalar üçün.
- View-model, UI, hesablama görünüşlərində rahat “virtual” property-lər üçün.
- Artıq mötərizəsiz .SomeCalculatedProperty kimi gözəl sintaksis istəyəndə.
2. C# 14-də yeni sintaksis
C# 14-də extension-lar üçün this açar sözündən imtina etdilər. Onun əvəzinə xüsusi extension(Type this) operatoru gəldi. Bununla artıq class-a yeni virtual üzvlər əlavə etmək olur.
Köhnə sintaksis
public static class StringExtensions
{
public static bool IsNullOrWhiteSpace(this string str)
=> string.IsNullOrWhiteSpace(str);
}
Yeni sintaksis
public static class Enumerable
{
extension(TSource source)
{
// Obyekt üçün virtual üzvlər
}
extension(TSource)
{
// Virtual statik üzvlər
}
}
3. Extension property-lərin sintaksisi
Necə görünür?
Tutaq ki, DateTime tipinə bir property əlavə etmək istəyirsən, hansı ki, tarix həftəsonudurmu, onu qaytaracaq:
public static class DateTimeExtensions
{
public static bool IsWeekend(this DateTime date) =>
date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday;
}
Amma bu köhnə Extension Method-dur və belə çağırılır: myDate.IsWeekend()
Yeni stil — Extension Property
public static class DateTimeExtensions
{
extension(DateTime source)
{
public bool IsWeekend // extension property!
{
get => source.DayOfWeek == DayOfWeek.Saturday || source.DayOfWeek == DayOfWeek.Sunday;
}
}
}
İndi belə yaza bilərsən:
DateTime today = DateTime.Now;
if (today.IsWeekend)
{
Console.WriteLine("Daha çox yatmaq olar!");
}
4. Extension property-lərin növləri
Təkcə read-only yox, həm də read-write property əlavə etmək olar:
public static class DateTimeExtensions
{
extension(DateTime source)
{
public int YearFrom1900 // extension property!
{
get => source.Year - 1900;
set => source.Year = value + 1900;
}
}
}
5. Statik property-lər
Yeni sintaksis sayəsində virtual property-ləri təkcə obyektə yox, həm də class-a əlavə etmək olur! Bəli, düz başa düşdün, artıq class-a virtual statik property əlavə edə bilərik. Sintaksis demək olar ki, eynidir:
public static class DateTimeExtensions
{
// Yeni sintaksis: DateTime üçün extension block (C# 14)
extension(DateTime)
{
// İstifadəçinin cari saat qurşağını saxlamaq üçün statik property
private static TimeZoneInfo _currentTimeZone = TimeZoneInfo.Local;
// Cari saat qurşağına çıxış üçün extension property
public static TimeZoneInfo CurrentTimeZone
{
get => _currentTimeZone;
set => _currentTimeZone = value ?? TimeZoneInfo.Local;
}
// İstifadəçi saat qurşağında vaxtı qaytarır
public DateTime InCurrentTimeZone
{
get => TimeZoneInfo.ConvertTime(this, CurrentTimeZone);
}
}
}
6. Nümunələr: Dog class-ını genişləndirək!
Gəlin, dərsdən dərsə çəkdiyimiz itlər tətbiqimizi inkişaf etdirək.
Tutaq ki, indi bizdə təkcə itlər yox, həm də onların peyvəndlərinin siyahısı var (List<DateTime>), amma Dog class-ı üçüncü tərəf kitabxanasındandır və kodunu dəyişə bilmirik. Biz property əlavə etmək istəyirik: Bütün vacib peyvəndlər bu il vurulub?
Köhnə üsul (extension metod):
public static class DogExtensions
{
public static bool AllVaccinatedThisYear(this Dog dog)
{
return dog.Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
// İstifadə:
if (myDog.AllVaccinatedThisYear())
Console.WriteLine("İt sağlamdır!");
Yeni üsul (extension property):
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// İstifadə:
if (myDog.AllVaccinatedThisYear)
Console.WriteLine("İt sağlamdır!");
Tam nümunə
// Dog class-ı — məsələn, üçüncü tərəf kitabxanasından:
public class Dog
{
public string Name { get; set; }
public List<DateTime> Vaccinations { get; set; } = new List<DateTime>();
}
// Extension block ilə extension class:
public static class DogExtensions
{
extension(Dog)
{
public bool AllVaccinatedThisYear
{
get => Vaccinations.Any(v => v.Year == DateTime.Now.Year);
}
}
}
// Proqramda:
var myDog = new Dog { Name = "Drujok" };
myDog.Vaccinations.Add(new DateTime(DateTime.Now.Year, 2, 16)); // bu il peyvənd
Console.WriteLine($"{myDog.Name}: vaksinasiya olunub? {(myDog.AllVaccinatedThisYear ? "Bəli" : "Xeyr")}");
7. Cədvəl: Extension metodlar vs Extension property-lər
| Extension metod | Extension property | |
|---|---|---|
| Çağırış sintaksisi | obj.Method() | obj.Property |
| Parametrləri ötürür | Bəli | Xeyr (yalnız this obj) |
| Yazmaq mümkündür | Tətbiq olunmur | Yalnız implement olunubsa |
| View/UI üçün rahatdır | Bəzən | Bəli (iki tərəfli binding, lambda) |
| Refleksiyada görünür | Xeyr | Xeyr |
8. Potensial tələlər və tipik səhvlər
Extension property-lər nə vaxt kömək etmir
- Onlar tam real field-i əvəz edə bilmir: obyektin private üzvlərinə çıxışı yoxdur.
- Avtomatik obyekt vəziyyətinin dəyişməsini əlavə etmək olmur (məsələn, əsas class-da dəyərin dəyişməsini birbaşa izləmək olmur).
- Extension property ilə interface və ya abstract class implement etmək olmur.
Adlarla bağlı səhv
Əgər birdən orijinal class-da sənin property-nin adı ilə eyni adla property yaranarsa, “öz” property istifadə olunacaq, sənin extension yox. Ona görə ad seçəndə diqqətli ol, xüsusilə .NET-in public tipləri ilə işləyəndə.
Seriyalizasiya/refleksiya problemləri
Extension property — bu, “real” tip üzvü deyil, sadəcə rahat sintaksisdir. Ona görə, əgər haradasa refleksiya və ya seriyalizasiya istifadə olunursa, extension property belə alətlər üçün görünməyə bilər.
GO TO FULL VERSION