CodeGym /Kurslar /C# SELF /C#-da qabaqcıl indeksatorlar: parametrlər, modifikatorlar...

C#-da qabaqcıl indeksatorlar: parametrlər, modifikatorlar, müasir imkanlar

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

1. Bir neçə parametrli indeksatorlar

Sadə indeksator (məsələn, this[int index]) o zaman faydalıdır ki, sənə elementlərə tam ədədi indekslə giriş lazımdır — demək olar ki, massiv kimi. Amma C# daha çox şeyə imkan verir: bir neçə parametrdən istifadə edə bilərsən, fərqli tipli parametrlər, get və set üçün fərqli giriş modifikatorları təyin edə bilərsən, bir sinifdə bir neçə indeksator reallaşdıra bilərsən (əgər imzaları fərqlidirsə).

Həmçinin yeni C# versiyalarında indeksatorlarla işləməyi asanlaşdıran əlavə imkanlar gəlib, o cümlədən kodu daha qısa yazmaq üçün sintaktik şəkər.

İndeksator heç də yalnız bir indeks və yalnız int tipində qəbul etməli deyil. Parametrləri sən təyin edirsən — və əgər sənin tapşırığına uyğundursa, bir neçə fərqli tipli parametr ola bilər.


public class ChessBoard
{
    private string[,] board = new string[8, 8];

    // İki parametrli indeksator!
    public string this[int row, int col]
    {
        get { return board[row, col]; }
        set { board[row, col] = value; }
    }
}
İki parametrli indeksator ikiölçülü struktur üçün

İndi kodu belə yaza bilərik:

ChessBoard chess = new ChessBoard();
chess[0, 0] = "Qala";
chess[7, 7] = "Şah";
string piece = chess[0, 0]; // "Qala"

Bu yanaşma matrislər, ikiölçülü xəritələr, stolüstü oyunlar, mürəkkəb kolleksiyalar üçün əladır.

2. Fərqli tipli parametrlərlə indeksatorlar

Sənin indeksatorun yalnız int yox, istənilən uyğun tipli parametr qəbul edə bilər. Əsas odur ki, bu, sənin tapşırığına məntiqli olsun.


using System.Collections.Generic;

public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Position { get; set; }
}

public class EmployeeCollection
{
    private List<Employee> employees = new List<Employee>();

    // İşçinin adına görə indeksator (string)
    public Employee this[string name]
    {
        get
        {
            foreach (var employee in employees)
            {
                if (employee.Name == name)
                    return employee;
            }
            return null; // Və ya istisna ata bilərsən
        }
        set
        {
            for (int i = 0; i < employees.Count; i++)
            {
                if (employees[i].Name == name)
                {
                    employees[i] = value;
                    return;
                }
            }
            // Əgər belə adla işçi yoxdursa — yenisini əlavə edirik
            employees.Add(value);
        }
    }

    // Uyğunluq üçün — ədədi indekslə indeksator
    public Employee this[int index]
    {
        get { return employees[index]; }
        set { employees[index] = value; }
    }
}
var company = new EmployeeCollection();
company[0] = new Employee { Name = "İvan", Age = 30, Position = "Proqramçı" };
company[1] = new Employee { Name = "Mariya", Age = 25, Position = "Dizayner" };

Employee employee = company["İvan"];
company["Petr"] = new Employee { Name = "Petr", Age = 28, Position = "Testçi" };

Vacibdir: əgər bir neçə indeksatorun varsa — onların imzaları parametr dəsti və tiplərinə görə fərqli olmalıdır.

3. get və set üçün fərqli giriş modifikatorları

Bəzən yalnız oxumağa icazə vermək, yazmağa isə qadağa qoymaq lazımdır (və ya əksinə). C#-da get və set aksesora fərqli giriş modifikatorları təyin edə bilərsən.


public class SecureEmployeeCollection
{
    private List<Employee> employees = new List<Employee>();

    public Employee this[int index]
    {
        get { return employees[index]; }
        internal set { employees[index] = value; }
    }
}

Bu, tez-tez kolleksiyaları icazəsiz dəyişikliklərdən qorumaq üçün istifadə olunur, sinifi daha idarəolunan edir.

4. Read-only və Write-only indeksatorlar

Bəzən istəyirsən ki, indeksatorla yalnız oxumaq və ya yalnız yazmaq mümkün olsun.


public class ReadOnlyEmployeeCollection
{
    private List<Employee> employees = new List<Employee>();

    public Employee this[int index]
    {
        get { return employees[index]; }
        // set yoxdur — dəyişmək olmaz!
    }
}

public class WriteOnlyEmployeeCollection
{
    private List<Employee> employees = new List<Employee>();

    public Employee this[int index]
    {
        set
        {
            employees.Insert(index, value);
        }
        // get yoxdur — oxumaq olmaz!
    }
}

Real layihələrdə "write-only" demək olar ki, rast gəlinmir: adətən "read-only" lazımdır, məsələn, sinifdən kənara yalnız baxmaq olar, amma indeksatorla məlumatı dəyişmək olmaz.

5. Sərhəd yoxlaması və məntiqi ilə indeksatorlar

Keyfiyyətli nümunələrdə yalnız indekslə giriş vermək yox, həm də sərhəddən çıxma, axtarış səhvləri və digər istisna halları düzgün işləmək vacibdir.


public class SafeEmployeeCollection
{
    private List<Employee> employees = new List<Employee>();

    public Employee this[int index]
    {
        get
        {
            if (index < 0 || index >= employees.Count)
                throw new IndexOutOfRangeException("Bu indekslə işçi mövcud deyil!");
            return employees[index];
        }
        set
        {
            if (index < 0 || index >= employees.Count)
                throw new IndexOutOfRangeException("Mövcud olmayan işçini əvəz etmək olmaz!");
            employees[index] = value;
        }
    }
}

null qaytara bilərsən və ya müasir yoxluq dəyərləri işləmə patternlərindən istifadə edə bilərsən — seçim sənin tətbiqinin məntiqindən asılıdır.

6. Qeyri-adi parametrlərlə indeksatorlar

Elə kolleksiyalar ola bilər ki, indeksator qeyri-standart tiplər qəbul edir: enum-lar (enum), istifadəçi strukturları, hətta bir neçə fərqli tipli parametr.


public enum Department { IT, HR, Finance, Marketing }

public class DepartmentEmployeeCollection
{
    private Dictionary<Department , Employee> departmentLeads = new Dictionary<Department , Employee>();

    public Employee this[Department  department]
    {
        get { return departmentLeads.TryGetValue(department, out var employee) ? employee : null; }
        set { departmentLeads[department] = value; }
    }
}
var company = new DepartmentEmployeeCollection();
company[Department.IT] = new Employee { Name = "Anna", Age = 35, Position = "IT rəhbəri" };
Employee itLead = company[Department.IT];

Bu yanaşma o zaman istifadə olunur ki, unikal identifikatorlar və ya tip və dəyər arasında dəqiq uyğunluq var — rahat, aydın və tip təhlükəsizdir.

7. Müasir imkanlar: Range və Index

Range və Index tipləri C# 8-də peyda olandan sonra indeksatorlar aralıqlarla və sondan indekslərlə işləmək üçün yeni imkanlar qazandı:


public class SmartArray
{
    private int[] numbers = Enumerable.Range(0, 100).ToArray();

    public int[] this[Range range] => numbers[range];
    public int this[Index index] => numbers[index];
}

// İstifadə:
var smart = new SmartArray();
int[] middle = smart[20..30]; // 20-dən 29-a qədər elementlər
int last = smart[^1]; // sonuncu element

Əgər öz kolleksiyanı reallaşdırırsansa, Range və Index dəstəyi onu maksimum "native" və developer üçün rahat edir.

8. Xüsusiyyətlər və indeksatorlar

Nə vaxt property, nə vaxt indeksator istifadə etməyi daha yaxşı başa düşmək üçün onların fərqlərini müqayisə etmək faydalıdır.

  • Property-lər obyektin fərdi xüsusiyyətlərinə ada görə giriş üçün rahatdır: person.Name, car.Speed.
  • İndeksatorlar kolleksiya və ya strukturun elementlərinə açarla giriş üçün uyğundur: employees[0], phoneBook["İvan"].
  • Property həmişə konkret ada malikdir və sinifdə yalnız bir property həmin adla ola bilər.
  • İndeksator this açar sözündən istifadə edir və imzaları fərqlidirsə, bir neçə variant ola bilər.
  • Property-lər statik ola bilər, indeksatorlar isə yox, çünki this həmişə konkret obyekt nümunəsinə işarə edir.

9. İndeksatorlarla işləyərkən tipik səhvlər

Səhv №1: sərhəd yoxlamasının olmaması.
Əgər indeksin massiv sərhədindən çıxmasını yoxlamasan, gözlənilməz anda IndexOutOfRangeException ala bilərsən.

Səhv №2: indeksatordan gələn mümkün null işlənmir.
Əgər sətir üzrə indeksator element yoxdursa null qaytarırsa, çağıran kod nəticəyə düşünmədən müraciət edirsə, NullReferenceException yaranır.

Səhv №3: indeksator imzalarının təkrarı.
C# eyni parametr dəsti ilə iki indeksator yaratmağa icazə vermir.

Səhv №4: set aksesorda qeyri-aşkar məntiq.
Əgər set-də "yoxdursa əlavə et" məntiqi istifadə olunursa, əvəzetmə yox, bu çaşdırıcı ola bilər. Belə həlləri açıq və yaxşı sənədləşdirmək lazımdır.

10. Praktiki tətbiq və nəticə

Real layihələrdə indeksatorlar tez-tez xüsusi kolleksiyalar, keşlər, əlavə məntiqli lüğətlər, matrislər və çoxölçülü məlumat strukturları yaratmaq üçün istifadə olunur. Onlar kodu daha oxunaqlı və intuitiv edir — məsələn, GetElementByIndex(5) tipli metod çağırışı əvəzinə sadəcə collection[5] yaza bilərsən.

Yadda saxla: indeksatorlar sənin sinifinin təbiətinə məntiqli uyğun olmalıdır. Əgər sinif kolleksiya və ya məlumat strukturu deyilsə, yəqin ki, indeksator lazım deyil. Amma əgər sinif elementlər toplusunu saxlayır və idarə edirsə, indeksator onu istifadə etməyi xeyli rahat və təbii edə bilər.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
İkiölçülü massiv üçün indeksatorun reallaşdırılması
İkiölçülü massiv üçün indeksatorun reallaşdırılması
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Enum ilə indeksator
Enum ilə indeksator
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION