مقدمه

به فصل یازدهم و بررسی ویژگی‌های پیشرفته‌تر زبان C# خوش آمدید. ما با نحوه‌ی دسترسی به عناصر یک آرایه یا List<T> با استفاده از براکت [] کاملاً آشنا هستیم. برای مثال، myArray[0] اولین عنصر آرایه را به ما می‌دهد. اما آیا تا به حال فکر کرده‌اید که چگونه می‌توانیم این قابلیت را برای کلاس‌های سفارشی خودمان نیز فراهم کنیم؟ ایندکسرها (Indexers) ویژگی قدرتمندی در C# هستند که دقیقاً همین کار را انجام می‌دهند. یک ایندکسر به اشیاء یک کلاس اجازه می‌دهد تا مانند یک آرایه یا کالکشن، ایندکس‌گذاری شوند. این کار دسترسی به داده‌های کپسوله‌شده در یک کلاس را بسیار طبیعی‌تر و شهودی‌تر می‌کند.

ایندکسر (Indexer) چیست؟

یک ایندکسر عضوی از کلاس است که به شما اجازه می‌دهد به یک شیء از آن کلاس مانند یک آرایه دسترسی پیدا کنید. در واقع، ایندکسرها نوعی "پراپرتی هوشمند" هستند. آن‌ها مانند پراپرتی‌ها دارای اکسسورهای get و set هستند، اما به جای یک نام مشخص، از کلمه‌ی کلیدی this به همراه یک یا چند پارامتر در داخل براکت [] برای تعریف خود استفاده می‌کنند. این پارامترها می‌توانند از هر نوعی باشند، نه فقط int، که این ویژگی ایندکسرها را بسیار انعطاف‌پذیر می‌کند.

تعریف یک ایندکسر

سینتکس تعریف یک ایندکسر بسیار شبیه به پراپرتی است. بیایید با یک مثال ساده شروع کنیم. فرض کنید کلاسی به نام Sentence داریم که یک جمله را در قالب آرایه‌ای از کلمات ذخیره می‌کند. ما می‌خواهیم بتوانیم به کلمات این جمله از طریق اندیس عددی آن‌ها دسترسی پیدا کنیم.

Copy Icon Program.cs
public class Sentence
{
    private string[] _words;

    public Sentence(string text)
    {
        _words = text.Split(' ');
    }

    // This is the indexer. It looks like a property but uses 'this[]'.
    public string this[int wordIndex]
    {
        get { return _words[wordIndex]; }
        set { _words[wordIndex] = value; }
    }
}

در این کد، ما یک ایندکسر تعریف کرده‌ایم که یک int به عنوان اندیس می‌پذیرد. اکسسور get کلمه‌ی موجود در آن اندیس از آرایه‌ی داخلی _words را برمی‌گرداند و اکسسور set به ما اجازه می‌دهد تا آن کلمه را تغییر دهیم.

استفاده از ایندکسر

اکنون می‌توانیم از یک نمونه‌ی کلاس Sentence مانند یک آرایه استفاده کنیم:

Copy Icon Program.cs
Sentence mySentence = new Sentence("Hello C# World");

// Use the indexer to get a value.
string secondWord = mySentence[1]; // Accesses the 'get' accessor.
Console.WriteLine(secondWord); // Output: C#

// Use the indexer to set a value.
mySentence[0] = "Greetings"; // Accesses the 'set' accessor.
Console.WriteLine(mySentence[0]); // Output: Greetings

ایندکسر با اندیس رشته‌ای

همانطور که گفته شد، اندیس یک ایندکسر محدود به اعداد صحیح نیست. شما می‌توانید از هر نوعی، مانند string، برای اندیس استفاده کنید. این قابلیت برای ساختن کلاس‌هایی که مانند یک دیکشنری عمل می‌کنند، بسیار مفید است.

Copy Icon Program.cs
public class CookieJar
{
    private readonly Dictionary<string, string> _cookies = new();

    // This indexer uses a string as its key.
    public string this[string cookieName]
    {
        get { return _cookies[cookieName]; }
        set { _cookies[cookieName] = value; }
    }
}

// --- Usage ---
CookieJar myCookies = new CookieJar();
myCookies["username"] = "alice";
myCookies["theme"] = "dark";

Console.WriteLine($"Username from cookie: {myCookies["username"]}");

در این مثال، کلاس CookieJar به ما اجازه می‌دهد تا با استفاده از یک کلید رشته‌ای، به مقادیر دسترسی پیدا کنیم. این سینتکس بسیار خواناتر و طبیعی‌تر از فراخوانی متدهایی مانند GetCookie("username") است.

سربارگذاری ایندکسرها

درست مانند متدها، ایندکسرها نیز می‌توانند سربارگذاری (overload) شوند. این یعنی شما می‌توانید چندین ایندکسر در یک کلاس داشته باشید، به شرطی که لیست پارامترهای آن‌ها (تعداد یا نوع اندیس‌ها) متفاوت باشد.

Copy Icon Program.cs
public class Schedule
{
    private string[] _dailyTasks = new string[7]; // 0=Sunday, 1=Monday...

    // Overload 1: Index by integer (day of week)
    public string this[int dayIndex]
    {
        get { return _dailyTasks[dayIndex]; }
        set { _dailyTasks[dayIndex] = value; }
    }

    // Overload 2: Index by string (day name)
    public string this[string dayName]
    {
        get { int dayIndex = GetDayIndex(dayName); return this[dayIndex]; }
        set { int dayIndex = GetDayIndex(dayName); this[dayIndex] = value; }
    }
    
    private int GetDayIndex(string name) { /* returns 0-6 based on name */ return 0; }
}

کلاس Schedule دو ایندکسر دارد: یکی که با عدد (0 تا 6) کار می‌کند و دیگری که با نام روز هفته (مثلاً "Sunday"). این به کاربر کلاس اجازه می‌دهد تا از هر روشی که برایش راحت‌تر است، استفاده کند.