使用索引子 (C# 程式設計手冊)

索引子的語法簡單明瞭,可讓您建立用戶端應用程式能夠以陣列形式存取的 classstructinterface。 編譯器將會產生 Item 屬性 (如有 IndexerNameAttribute,則會產生具名屬性) 及適當的存取子方法。 索引子最常實作於類型中,而類型的主要用途是封裝內部集合或陣列。 例如,假設您有類別 TempRecord 會指出 24 小時期間內,10 個不同時間的華氏溫度記錄。 此類別包含類型為 float[] 的陣列 temps,可以儲存溫度值。 透過在此類別中實作索引子,用戶端能以 TempRecord 執行個體中 float temp = tempRecord[4] 的形式 (而非 float temp = tempRecord.temps[4]) 來存取溫度。 索引子標記法不只簡化了用戶端應用程式的語法,還能讓其他開發人員更容易了解此類別及其用途。

若要在類別或結構上宣告索引子,請使用 this 關鍵字,如下列範例所示:

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

重要

宣告索引子會自動為物件產生名為 Item 的屬性。 Item 屬性無法直接從執行個體成員存取運算式直接存取。 此外,若您將自己的 Item 屬性,新增至包含索引子的物件,將會收到 CS0102 編譯器錯誤。 若要避免此錯誤,請使用 IndexerNameAttribute 重新命名索引子,如下所示。

備註

索引子類型和其參數類型至少必須可以像索引子本身一樣地存取。 如需存取範圍層級的詳細資訊,請參閱存取修飾詞

如需如何搭配使用索引子與介面的詳細資訊,請參閱介面索引子

索引子的簽章包含其型式參數的數目和類型。 它不包含索引子類型或正式參數的名稱。 如果您在相同的類別中宣告多個索引子,則它們必須具有不同的簽章。

索引子不屬於變數;因此,除非索引子值為參考 (亦即由參考傳回),否則無法透過參考 (refout 參數) 傳遞。

若要以其他語言可使用的名稱提供索引子,請使用 System.Runtime.CompilerServices.IndexerNameAttribute,如下列範例所示:

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

因為索引子名稱屬性會覆寫此索引子的名稱,所以其名稱會是 TheItem。 根據預設,此索引子的名稱為 Item

範例 1

下列範例示範如何宣告私用陣列欄位 temps 和索引子。 索引子可讓您直接存取執行個體 tempRecord[i]。 使用索引子的替代方式是將陣列宣告為 public 成員,並直接存取其成員 tempRecord.temps[i]

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;
    }
}

請注意,評估索引子的存取時 (例如,在 Console.Write 陳述式中),會叫用 get 存取子。 因此,如果沒有 get 存取子,就會發生編譯時間錯誤。

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]}");
}

使用其他值編製索引

C# 不會將索引子參數類型限制為整數。 例如,搭配使用字串與索引子可能十分有用。 在集合中搜尋字串,並傳回適當的值,可能會實作這類索引子。 存取子有可能多載,因此可能會有多種版本的字串和整數並存。

範例 2

下列範例宣告的類別會儲存週中的日。 get 存取子接受字串 (日的名稱),並傳回對應的整數。 例如,"Sunday" 會傳回 0,"Monday" 會傳回 1,依此類推。

// 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");
    }
}

取用範例 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}");
}

範例 3

下列範例宣告的類別,會儲存使用 System.DayOfWeek 列舉的週間日。 get 存取子接受 DayOfWeek (週間日的值),並會傳回對應的整數。 例如,DayOfWeek.Sunday 會傳回 0、DayOfWeek.Monday 日傳回 1 等等。

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.");
    }
}

取用範例 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}");
}

穩固程式設計

有兩種主要的方式可以改善索引子的安全性和可靠性:

  • 請務必包含某種類型的錯誤處理策略來處理用戶端程式碼傳入無效索引值的機會。 在本主題稍早的第一個範例中,TempRecord 類別提供 Length 屬性,以讓用戶端程式碼先確認輸入,再將其傳遞給索引子。 您也可以將錯誤處理程式碼放在索引子本身內。 請務必為使用者記載您在索引子存取子內擲回的任何例外狀況。

  • getset 存取子的存取範圍設定為合理限制。 這對 set 存取子特別重要。 如需詳細資訊,請參閱限制存取子的存取範圍

另請參閱