Menggunakan pengindeks (Panduan Pemrograman C#)

Pengindeks adalah kemudahan sintaksis yang memungkinkan Anda membuat kelas, struct, atau antarmuka yang dapat diakses aplikasi klien sebagai larik. Kompilator akan menghasilkan properti Item (atau properti bernama alternatif jika IndexerNameAttribute ada), dan metode pengakses yang sesuai. Pengindeks paling sering diterapkan dalam jenis yang tujuan utamanya adalah untuk menyertakan koleksi atau larik internal. Misalnya, Anda memiliki kelas TempRecord yang mewakili suhu dalam Fahrenheit sebagaimana dicatat pada 10 waktu berbeda selama periode 24 jam. Kelas berisi larik temps berjenis float[] untuk menyimpan nilai suhu. Dengan menerapkan pengindeks di kelas ini, klien dapat mengakses suhu dalam instans TempRecord sebagai float temp = tempRecord[4], bukan sebagai float temp = tempRecord.temps[4]. Notasi pengindeks tidak hanya menyederhanakan sintaks untuk aplikasi klien; notasi pengindeks juga membuat kelas, dan tujuannya lebih intuitif untuk dipahami oleh pengembang lain.

Untuk mendeklarasikan pengindeks pada kelas atau struct, gunakan kata kunci this, seperti yang ditunjukkan contoh berikut:

// Indexer declaration
public int this[int index]
{
    // get and set accessors
}

Penting

Mendeklarasikan pengindeks akan secara otomatis menghasilkan properti bernama Item pada objek. Properti Item tidak dapat diakses secara langsung dari ekspresi akses anggota instans. Selain itu, jika Anda menambahkan properti Item Anda sendiri ke objek dengan pengindeks, Anda akan mendapatkan kesalahan kompilator CS0102. Untuk menghindari kesalahan ini, gunakan IndexerNameAttribute ganti nama pengindeks seperti yang dijelaskan di bawah ini.

Keterangan

Jenis pengindeks dan jenis parameternya harus setidaknya dapat diakses seperti pengindeks itu sendiri. Untuk informasi selengkapnya tentang tingkat aksesibilitas, lihat Pengubah Akses.

Untuk informasi selengkapnya tentang cara menggunakan pengindeks dengan antarmuka, lihat Pengindeks Antarmuka.

Tanda tangan pengindeks terdiri dari jumlah dan jenis parameter formal pengindeks. Tanda tangan pengindeks tidak termasuk jenis pengindeks atau nama parameter formal. Jika Anda mendeklarasikan lebih dari satu pengindeks di kelas yang sama, pengindeks harus memiliki tanda tangan yang berbeda.

Pengindeks tidak diklasifikasikan sebagai variabel; oleh karena itu, nilai pengindeks tidak dapat diteruskan oleh referensi (sebagai ref parameter) out kecuali nilainya adalah referensi (yaitu, nilai tersebut dikembalikan oleh referensi.)

Untuk memberi pengindeks nama yang dapat digunakan bahasa lain, gunakan System.Runtime.CompilerServices.IndexerNameAttribute, seperti yang ditunjukkan contoh berikut:

// Indexer declaration
[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this[int index]
{
    // get and set accessors
}

Pengindeks ini akan memiliki nama TheItem, karena ditimpa oleh atribut nama pengindeks. Secara default, nama pengindeks adalah Item.

Contoh 1

Contoh berikut menunjukkan cara mendeklarasikan bidang larik privat, temps, dan pengindeks. Pengindeks memungkinkan akses langsung ke instans tempRecord[i]. Alternatif untuk menggunakan pengindeks adalah mendeklarasikan larik sebagai anggota publik dan mengakses anggota larik, tempRecord.temps[i], secara langsung.

public class TempRecord
{
    // Array of temperature values
    float[] temps =
    [
        56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
        61.3F, 65.9F, 62.1F, 59.2F, 57.5F
    ];

    // To enable client code to validate input
    // when accessing your indexer.
    public int Length => temps.Length;
    
    // Indexer declaration.
    // If index is out of range, the temps array will throw the exception.
    public float this[int index]
    {
        get => temps[index];
        set => temps[index] = value;
    }
}

Perhatikan bahwa ketika akses pengindeks dievaluasi, misalnya, dalam pernyataan Console.Write, pengakses get dipanggil. Oleh karena itu, jika pengakses get tidak ada, kesalahan waktu kompilasi akan terjadi.

var tempRecord = new TempRecord();

// Use the indexer's set accessor
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;

// Use the indexer's get accessor
for (int i = 0; i < 10; i++)
{
    Console.WriteLine($"Element #{i} = {tempRecord[i]}");
}

Pengindeksan menggunakan nilai lain

C# tidak membatasi jenis parameter pengindeks ke bilangan bulat. Misalnya, mungkin berguna untuk menggunakan string dengan pengindeks. Pengindeks semacam itu dapat diterapkan dengan mencari string dalam koleksi, dan mengembalikan nilai yang sesuai. Karena pengakses dapat kelebihan beban, versi string dan bilangan bulat dapat berdampingan.

Contoh 2

Contoh berikut mendeklarasikan kelas yang menyimpan hari-hari dalam seminggu. Pengakses get mengambil string, nama hari, dan mengembalikan bilangan bulat yang sesuai. Misalnya, "Minggu" menampilkan 0, "Senin" menampilkan 1, dan seterusnya.

// Using a string as an indexer value
class DayCollection
{
    string[] days = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"];

    // Indexer with only a get accessor with the expression-bodied definition:
    public int this[string day] => FindDayIndex(day);

    private int FindDayIndex(string day)
    {
        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == day)
            {
                return j;
            }
        }

        throw new ArgumentOutOfRangeException(
            nameof(day),
            $"Day {day} is not supported.\nDay input must be in the form \"Sun\", \"Mon\", etc");
    }
}

Menggunakan contoh 2

var week = new DayCollection();
Console.WriteLine(week["Fri"]);

try
{
    Console.WriteLine(week["Made-up day"]);
}
catch (ArgumentOutOfRangeException e)
{
    Console.WriteLine($"Not supported input: {e.Message}");
}

Contoh 3

Contoh berikut mendeklarasikan kelas yang menyimpan hari dalam seminggu menggunakan enum System.DayOfWeek. Pengakses get mengambil DayOfWeek, nilai hari, dan mengembalikan bilangan bulat yang sesuai. Misalnya, DayOfWeek.Sunday menampilkan 0, DayOfWeek.Monday menampilkan 1, dan seterusnya.

using Day = System.DayOfWeek;

class DayOfWeekCollection
{
    Day[] days =
    [
        Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday,
        Day.Thursday, Day.Friday, Day.Saturday
    ];

    // Indexer with only a get accessor with the expression-bodied definition:
    public int this[Day day] => FindDayIndex(day);

    private int FindDayIndex(Day day)
    {
        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == day)
            {
                return j;
            }
        }
        throw new ArgumentOutOfRangeException(
            nameof(day),
            $"Day {day} is not supported.\nDay input must be a defined System.DayOfWeek value.");
    }
}

Menggunakan contoh 3

var week = new DayOfWeekCollection();
Console.WriteLine(week[DayOfWeek.Friday]);

try
{
    Console.WriteLine(week[(DayOfWeek)43]);
}
catch (ArgumentOutOfRangeException e)
{
    Console.WriteLine($"Not supported input: {e.Message}");
}

Pemrograman yang kuat

Ada dua cara utama untuk meningkatkan keamanan dan keandalan pengindeks:

  • Pastikan untuk memasukkan beberapa jenis strategi penanganan kesalahan untuk menangani kemungkinan kode klien melewati nilai indeks yang tidak valid. Dalam contoh pertama sebelumnya dalam topik ini, kelas TempRecord menyediakan properti Panjang yang memungkinkan kode klien untuk memverifikasi input sebelum meneruskannya ke pengindeks. Anda juga dapat meletakkan kode penanganan kesalahan di dalam pengindeks itu sendiri. Pastikan untuk mendokumentasikan untuk pengguna pengecualian apa pun yang Anda masukkan ke dalam pengakses pengindeks.

  • Atur aksesibilitas pengakses get dan set menjadi sebatas wajar. Hal ini penting bagi pengakses set khususnya. Untuk informasi selengkapnya, lihat Membatasi Aksesibilitas Pengakses.

Lihat juga