CodeGym /Kurslar /C# SELF /Type-larla işləmək: is, as və Pattern Matching

Type-larla işləmək: is, as və Pattern Matching

C# SELF
Səviyyə, Dərs
Mövcuddur

1. is operatoru: Tip uyğunluğunu yoxlamaq

Real tətbiqlərdə tez-tez belə olur ki, səndə baz tipinə referans var, amma bilirsən və ya şübhələnirsən ki, əslində yaddaşda olan obyekt daha spesifik törəmə tipdir. Belə hallarda həmin törəmə tipin unikal üzvlərinə çıxış lazım ola bilər. Belə situasiyalarda təhlükəsiz və rahat işləmək üçün C#-da əsas alətlər var: is, as operatorları və xüsusilə müasir dillərdə güclü pattern matching imkanları.

is operatoru yoxlayır ki, obyekt göstərilən tipin, onun törəməsinin nümunəsidir, ya da müəyyən interfeysi reallaşdırır. Əgər obyekt bu tiplə uyğun gəlirsə, true, yoxsa false qaytarır.

Əsas istifadə: obyektin müəyyən tipə təhlükəsiz çevrilib-çevrilə bilməyəcəyini yoxlamaq.

Nümunə: Baza tipi və irsi yoxlamaq


class Animal { public string Species { get; set; } = "Naməlum"; }
class Dog : Animal { public void Bark() => Console.WriteLine("Hav-hav!"); }
class Cat : Animal { public void Meow() => Console.WriteLine("Miyav!"); }

Animal myAnimal = new Dog { Species = "Golden Retriever" };

Console.WriteLine($"myAnimal is Animal: {myAnimal is Animal}"); // True
Console.WriteLine($"myAnimal is Dog: {myAnimal is Dog}");       // True
Console.WriteLine($"myAnimal is Cat: {myAnimal is Cat}");       // False

Bu nümunədə myAnimal əslində Dog-dur. Ona görə də myAnimal is Animal və myAnimal is Dog true qaytaracaq.

Nümunə: null yoxlamaq

is operatoru null ilə də gözlənilən kimi işləyir.


Animal nullAnimal = null;
Dog specificDog = new Dog();

Console.WriteLine($"nullAnimal is Animal: {nullAnimal is Animal}"); // False (null heç bir tipin nümunəsi deyil)
Console.WriteLine($"specificDog is null: {specificDog is null}");   // False (obyekt null deyil)

Diqqət et, null heç bir tipin nümunəsi deyil, ona görə də null is MyType həmişə false olacaq. Amma someObject is null — referansın null olub-olmadığını yoxlamaq üçün rahat və təhlükəsiz üsuldur.

Nümunə: is operatorunu interfeyslərlə istifadə etmək

is operatoru interfeys reallaşdırmasını da yoxlaya bilir.


interface IFlyable { void Fly(); }
class Bird : Animal, IFlyable { public void Fly() => Console.WriteLine("Qanad çırpır!"); }
class Fish : Animal { }

Animal creature = new Bird();

Console.WriteLine($"creature is Bird: {creature is Bird}");     // True
Console.WriteLine($"creature is IFlyable: {creature is IFlyable}"); // True

creature = new Fish();
Console.WriteLine($"creature is IFlyable: {creature is IFlyable}"); // False

2. as operatoru: Tipi təhlükəsiz çevirmək

as operatoru obyekti göstərilən tipə təhlükəsiz çevirmək üçündür. (Type)obj kimi açıq çevirmədən fərqli olaraq, hansı ki, uğursuz olsa InvalidCastException atır, as çevirmə mümkün deyilsə null qaytarır. Bu, obyektin əsl tipinə əmin olmadığın hallarda idealdır.

Əsas istifadə: Tip çevirməyə cəhd etmək, uğursuz olarsa null almaq.

Nümunə: as operatorunun əsas istifadəsi


class Shape { }
class Circle : Shape { public double Radius { get; set; } }
class Square : Shape { public double Side { get; set; } }

Shape myShape = new Circle { Radius = 5.0 };

// Circle tipinə çevirməyə cəhd
Circle circle = myShape as Circle;
if (circle != null) // Mütləq null yoxlaması!
{
    Console.WriteLine($"Bu dairədir, radiusu: {circle.Radius}"); // Çıxış: Bu dairədir, radiusu: 5
}

// Square tipinə çevirməyə cəhd
Square square = myShape as Square;
if (square == null) // Çevirmə alınmadı, square == null
{
    Console.WriteLine("Bu kvadrat deyil."); // Çıxış: Bu kvadrat deyil.
}

Gördüyün kimi, as run-time səhvlərdən qaçmağa kömək edir, çünki uğursuzluqda null qaytarır.

Nümunə: as operatorunun məhdudiyyətləri

Vacibdir ki, as operatoru yalnız referans tipləri və nullable value tipləri ilə işləyir. O, adi value tiplərinə tətbiq edilə bilməz, çünki onlar null ala bilmir.


object someValue = 100;

int num = someValue as int; // KOMPİLYASİYA SƏHVi: 'as' null olmayan tiplərlə işləyə bilmir
int? nullableNum = someValue as int?; // Ok, nullable int
Console.WriteLine($"Nullable int: {nullableNum}"); // Çıxış: Nullable int: 100

string str = someValue as string; // null qaytarır, çünki 100 string deyil
Console.WriteLine($"String from int: {str ?? "null"}"); // Çıxış: String from int: null

Null olmayan value tipləri üçün ya açıq çevirmə ((int)someValue) istifadə et (əgər tipə əminsənsə və exception almağa hazırsansa), ya da daha yaxşısı, pattern matching-dən istifadə et.

3. Pattern Matching (Şablonla uyğunlaşdırma)

Pattern matching — tip yoxlama və obyektlərdən məlumat çıxarmaq üçün daha zərif və təhlükəsiz üsullar verən güclü və inkişaf edən funksiyadır. O, kodu xeyli qısaldır və oxunaqlılığı artırır.

Type Pattern (is ilə tip şablonu)

Bu, pattern matching-in ən çox istifadə olunan formasıdır: obyektin tipini yoxlayır və əgər uyğun gəlirsə, onu göstərilən tipdə yeni dəyişənə təyin edir.

Syntax: ifadə is Tip dəyişən

Nümunə: is + çevirmənin əvəzi


// Shape, Circle, Square class-ları ilə davam edirik

Shape currentShape = new Circle { Radius = 7.5 };

// Köhnə, uzun yol:
if (currentShape is Circle)
{
    Circle c = (Circle)currentShape;
    Console.WriteLine($"Köhnə yol: Dairə, radiusu {c.Radius}");
}

// Yeni, zərif yol type pattern ilə
if (currentShape is Circle c) // Tip yoxlama və 'c' dəyişəni yaratmaq
{
    Console.WriteLine($"Yeni yol: Dairə, radiusu {c.Radius}"); // 'c' artıq Circle tipindədir
}

Shape anotherShape = new Square { Side = 10.0 };
if (anotherShape is Square s)
{
    Console.WriteLine($"Bu kvadratın tərəfi {s.Side}");
}

c (və ya s) dəyişəni yalnız if blokunda əlçatandır, bu da onu səhvən başqa yerdə istifadə etməyin qarşısını alır.

Property Pattern (Property şablonu)

C# 8.0-dan başlayaraq, sən təkcə tipi yox, həm də obyektin bir və ya bir neçə property-sinin dəyərini yoxlaya və onları yeni dəyişənlərə çıxara bilərsən.

Syntax: ifadə is Tip { Property1: dəyər_şablonu, Property2: çıxarılan_dəyişən }

Nümunə: Property yoxlamaq


Shape testShape = new Circle { Color = "Yaşıl", Radius = 12.0 };

// Obyektin dairə olub-olmadığını və rənginin yaşıl olduğunu yoxlayırıq
if (testShape is  Circle { Color: "Yaşıl" })
{
    Console.WriteLine("Yaşıl dairə tapıldı.");
}

// Obyektin dairə olub-olmadığını yoxlayırıq və radiusunu çıxarırıq
if (testShape is  Circle { Radius: var r })
{
    Console.WriteLine($"Radius çıxarıldı: {r}");
}

// Yoxlama və çıxarma bir yerdə:
if (testShape is  Circle { Color: "Yaşıl", Radius: var radiusVal } circleObj)
{
    Console.WriteLine($"Yaşıl dairə çıxarıldı. Radius: {radiusVal}, Obyekt: {circleObj.Radius}");
}

Property pattern mürəkkəb şərtləri xeyli sadələşdirir.

Nümunə: Property Pattern-lərdə interval və məntiqi operatorlar

İndi obyektin property-lərinin müəyyən şərtə uyğun olub-olmadığını yoxlaya bilərsən:


Circle bigCircle = new Circle { Radius = 25.0, Color = "Mavi" };

// Radiusu 20-dən böyük VƏ rəngi mavi
if (bigCircle is Circle { Radius: > 20, Color: "Mavi" })
{
    Console.WriteLine("Böyük mavi dairə tapıldı.");
}

// Radiusu (5..15) aralığında
if (testShape is Circle { Radius: >= 5 and <= 15 })
{
    Console.WriteLine("Orta ölçülü dairə.");
}

Vacib! bool tipindən fərqli olaraq, burada and, or və not açar sözləri istifadə olunur.

4. Switch Expressions və Switch Statements pattern matching ilə

Pattern matching-in ən çevik və oxunaqlı istifadəsi switch operatorlarında olur. Onlar uyğun şablona görə müxtəlif məntiqi yerinə yetirməyə imkan verir.

Nümunə: Switch Statement

Hər uyğun şablon üçün kod blokları təyin etməyə imkan verir.


// Animal, Dog, Cat class-ları əvvəlki kimi
Animal currentCreature = new Dog { Species = "Poodle" };

switch (currentCreature)
{
    case Dog d: // Tip şablonu: əgər Dog-dursa, 'd' dəyişəninə təyin et
        d.Bark();
        Console.WriteLine($"Bu {d.Species} cinsli itdir.");
        break;
    case Cat c when c.Species == "Siamese": // Tip şablonu və şərt (when clause)
        c.Meow();
        Console.WriteLine($"Bu siam pişiyidir.");
        break;
    case Animal a: // Sadəcə Animal-dırsa (Dog/Cat deyil)
        Console.WriteLine($"Bu sadəcə {a.Species} növ heyvandır.");
        break;
    case null: // Null şablonu, null dəyərləri işləmək üçün
        Console.WriteLine("Obyekt null-dır.");
        break;
    default: // Heç biri uyğun gəlmirsə
        Console.WriteLine("Naməlum varlıq.");
        break;
}

switch-də case-lərin sırası vacibdir: daha spesifik şablonlar ümumilərdən əvvəl olmalıdır.

Nümunə: Switch Expression

Bu, switch-in daha qısa sintaksisidir və dəyər qaytarır. Obyekti tipinə və ya property-lərinə görə başqa dəyərə çevirmək üçün idealdır.

Syntax: ifadə switch { şablon1 => nəticə1, şablon2 => nəticə2, ... _ => default_nəticə }


Shape processShape = new Rectangle { Width = 5, Height = 5, Color = "Qırmızı" };

string shapeInfo = processShape switch
{
    Circle { Radius: var r } when r > 10 => $"Böyük dairə (R={r})", // Property şablonu və şərt
    Circle { Color: "Mavi" } c =>  $"Mavi dairə (R={c.Radius})",   // Property şablonu və çıxarma
    Circle c =>  $"Adi dairə (R={c.Radius})",                     // Sadə tip şablonu
    Rectangle { Width: var w, Height: var h } when w == h =>  $"Kvadrat ({w}x{h})", // Kvadrat
    Rectangle r =>  $"Düzbucaqlı ({r.Width}x{r.Height})",         // Digər düzbucaqlı
    null =>  "Fiqur yoxdur (null)",                           // Null şablonu
    _ =>  "Naməlum fiqur"                                     // Diskard şablonu (_), 'default' əvəzinə
};

Console.WriteLine(shapeInfo); // Çıxış: Kvadrat (5x5)

switch expression qısa və ifadəli çevirmələr üçün çox rahatdır.

Var Pattern (var şablonu)

C# 7.0-dan başlayaraq pattern matching-də var istifadə edə bilərsən. var istənilən obyektlə (yalnız null istisna olmaqla) uyğun gəlir və onu uyğun tipdə dəyişənə çıxarır.

Nümunə: var Pattern istifadə etmək


object obj = "Salam Dünya";

if (obj is var  result) // Həmişə true, result string olacaq
{
    Console.WriteLine($"Tip: {result.GetType().Name}, Dəyər: {result}");
}

obj = 123;
string typeName = obj switch
{
    var x when x is int => "Bu tam ədəddir",
    var y when y is string =>  "Bu sətrdir",
    _ => "Başqa bir şey"
};
Console.WriteLine(typeName); // Çıxış: Bu tam ədəddir

var Pattern təkcə tip yoxlamaq üçün nadir hallarda istifadə olunur, amma digər şablonlarda və ya switch-də dəyəri çıxarmaq üçün çox faydalıdır.

5. is vs as vs Pattern Matching: nə vaxt hansını istifadə etməli?

Alətin seçimi sənin konkret tapşırığından və istifadə etdiyin C# versiyasından asılıdır.

is operatoru (sadə):

İstifadə: Sadəcə obyektin müəyyən tip olub-olmadığını yoxlamaq lazımdırsa və dərhal çevirməyə və ya spesifik üzvlərə çıxış lazım deyilsə.


    if (myObject is SomeType)

as operatoru:

İstifadə: Referans tipini (və ya nullable value tipini) çevirməyə cəhd edirsən və uğursuzluqda exception yox, null almaq istəyirsən.


    MyDerivedClass derived = myBaseObject as MyDerivedClass;
if (derived != null) { /* ... */ }

Pattern Matching (is Type variable):

Müasir üstünlük verilən yanaşma: Tip yoxlama və təhlükəsiz çevirməni bir, oxunaqlı sətrdə birləşdirir. Bütün tiplər üçün işləyir.

İstifadə: Tipi yoxlayıb dərhal həmin tipin spesifik üzvlərindən istifadə etmək lazım olanda.


    if (myObject is MyDerivedClass derived) { derived.SpecificMethod(); }

Pattern Matching (switch expressions / statements):

Müasir üstünlük verilən yanaşma: Obyektin tipinə, property-lərinə və ya digər xüsusiyyətlərinə görə müxtəlif əməliyyatlar və ya dəyərlər almaq lazım olanda. Bu, uzun if-else if zəncirlərindən xeyli təmizdir.

İstifadə: Obyektin xüsusiyyətlərinə əsaslanan polimorf davranış və ya mürəkkəb seçim məntiqi qurmaq.


string GetShapeInfo(Shape s) => s switch
{
    Circle c => $"Dairə R={c.Radius}",
    Rectangle r => $"Düzbucaqlı W={r.Width} H={r.Height}",
    _ => "Naməlum"
};
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Obyektin tipinin `is` operatoru ilə yoxlanılması
Obyektin tipinin `is` operatoru ilə yoxlanılması
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Gecikdirilmiş icra
Kolleksiyalarla işləmənin optimallaşdırılması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION