Verwenden von Indexern (C#-Programmierhandbuch)

Indexer sind ein syntaktisches Hilfsmittel, um Ihnen die Erstellung einer Klasse, einer Struktur, oder einer Schnittstelle zu ermöglichen, auf die Clientanwendungen wie auf ein Array zugreifen können. Indexer werden am häufigsten in Typen implementiert, deren Hauptzweck darin besteht, eine interne Auflistung oder ein Array zu kapseln. Angenommen Sie verfügen über eine Klasse mit dem Namen .TempRecord, zur Darstellung der Temperatur in Fahrenheit zu 10 verschiedenen Zeitpunkten während eines 24-stündigen Zeitraums. Die Klasse enthält ein Array mit dem Namen "Temps" vom "float"-Datentyp, um die Temperaturen darzustellen, und einen <xref:System.DateTime>, der das Datum darstellt, an welchem die Temperaturen erfasst wurden. Durch die Implementierung eines Indexers in dieser Klasse, können Clients auf die Temperaturen in einer TempRecord-Instanz als float temp = tr[4] zugreifen, statt als float temp = tr.temps[4]. Die Angabe des Indexers vereinfacht nicht nur die Syntax für Clientanwendungen; die Klasse und Ihr Zweck können außerdem intuitiver von anderen Entwicklern verstanden werden.

Um einen Indexer auf eine Klasse oder Struktur zu deklarieren, verwenden Sie das this -Schlüsselwort, wie im folgenden Beispiel:

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

Hinweise

Der Typ eines Indexers und der Typ seiner Parameter müssen zumindest dieselben Zugriffsmöglichkeiten bieten wie der Indexer selbst. Weitere Informationen zu den Zugriffsebenen finden Sie unter Zugriffsmodifizierer.

Weitere Informationen zum Verwenden von Indexern mit einer Schnittstelle finden Sie unter Schnittstellenindexer.

Die Signatur eines Indexers besteht aus der Anzahl und den Typen seiner formalen Parameter. Sie umfasst nicht den Indexertyp oder die Namen der formalen Parameter. Wenn Sie mehrere Indexer in derselben Klasse deklarieren, müssen sie verschiedene Signaturen aufweisen.

Ein Indexerwert wird nicht als Variable klassifiziert. Aus diesem Grund können Sie keinen Indexerwert als Ref- oder out-Parameter übergeben.

Um dem Indexer einen Namen zu geben, den andere Sprachen verwenden können, verwenden Sie ein name-Attribut in der Deklaration. Zum Beispiel:

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

Dieser Indexer hat den Namen TheItem. Wird kein Namensattribut bereitgestellt, wird Item zum Standardnamen.

Beispiel 1

Beschreibung

Im folgenden Beispiel wird die Deklaration eines öffentlichen Arrayfelds, temps, und eines Indexers dargestellt. Der Indexer ermöglicht den direkten Zugriff auf die Instanz tempRecord[i]. Als Alternative zur Verwendung des Indexers, kann das Array als öffentliches Mitglied deklariert und direkt auf dessen Mitglieder, tempRecord.temps[i], zugegriffen werden.

Beachten Sie, dass, wenn der Zugriff eines Indexers, z.B. in einer Console.Write-Anweisung ausgewertet wird, der get-Accessor aufgerufen wird. Wenn kein get-Accessor vorhanden ist, tritt deshalb ein Kompilierzeitfehler auf.

Code

class TempRecord
{
    // Array of temperature values
    private float[] temps = new float[10] { 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
    {
        get { return temps.Length; }
    }
    // Indexer declaration.
    // If index is out of range, the temps array will throw the exception.
    public float this[int index]
    {
        get
        {
            return temps[index];
        }

        set
        {
            temps[index] = value;
        }
    }
}

class MainClass
{
    static void Main()
    {
        TempRecord 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++)
        {
            System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
        }

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();

    }
}
/* Output:
        Element #0 = 56.2
        Element #1 = 56.7
        Element #2 = 56.5
        Element #3 = 58.3
        Element #4 = 58.8
        Element #5 = 60.1
        Element #6 = 65.9
        Element #7 = 62.1
        Element #8 = 59.2
        Element #9 = 57.5
    */

Indizieren mit anderen Werten

C# beschränkt den Typ des Indexes nicht auf Integer. Beispielsweise kann es sinnvoll sein, eine Zeichenfolge mit einem Indexer zu verwenden. Ein solcher Indexer kann implementiert werden, indem die Zeichenfolge in der Auflistung gesucht und der richtige Wert zurückgegeben wird. Da Accessoren überladen werden können, können die Zeichenfolge- und die Integer-Version zusammen verwendet werden.

Beispiel 2

Beschreibung

In diesem Beispiel wird eine Klasse deklariert, die die Wochentage speichert. Ein get-Accessor wird deklariert, der eine Zeichenfolge und den Namen eines Tages annimmt, und den entsprechenden Integer zurückgibt. Z.B. gibt Sonntag 0 zurück, Montag gibt 1 zurück, usw.

Code

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

    // This method finds the day or returns -1
    private int GetDay(string testDay)
    {

        for (int j = 0; j < days.Length; j++)
        {
            if (days[j] == testDay)
            {
                return j;
            }
        }

        throw new System.ArgumentOutOfRangeException(testDay, "testDay must be in the form \"Sun\", \"Mon\", etc");
    }

    // The get accessor returns an integer for a given string
    public int this[string day]
    {
        get
        {
            return (GetDay(day));
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        DayCollection week = new DayCollection();
        System.Console.WriteLine(week["Fri"]);

        // Raises ArgumentOutOfRangeException
        System.Console.WriteLine(week["Made-up Day"]);

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }
}
// Output: 5

Stabile Programmierung

Es gibt zwei grundlegende Möglichkeiten, mit denen die Sicherheit und die Zuverlässigkeit von Indexern verbessert werden kann:

  • Integrieren Sie irgendeine Form von Fehlerbehandlungsstrategie, für den Fall, dass Clientcode in einem ungültigen Indexwert übergeben wird. Im ersten Beispiel weiter oben in diesem Thema stellt die TempRecord-Klasse eine Length-Eigenschaft bereit, die dem Clientcode ermöglicht, die Eingabe vor der Übergabe an den Indexer zu überprüfen. Sie können den Fehlerbehandlungscode auch in den Indexer selbst einfügen. Achten Sie darauf alle Ausnahmen, die Sie innerhalb eines Indexeraccessors auslösen, für Benutzer zu dokumentieren.

  • Schränken Sie den Zugriff auf den get- und set-Accessor so ein, dass die Beschränkung angemessen ist. Dies ist insbesondere wichtig für den set-Accessor. Weitere Informationen finden Sie unter Einschränken des Accessorzugriffs.

Siehe auch

C#-Programmierhandbuch
Indexer
Eigenschaften