Verwenden von Indexern (C#-Programmierhandbuch)
Aktualisiert: November 2007
Bei Indexern handelt es sich um ein syntaktisches Hilfsmittel, mit dem Sie Klassen, Strukturen und Schnittstellen erstellen können, auf die Clientanwendungen wie auf ein Array zugreifen können. Indexer werden am häufigsten in Typen implementiert, deren Hauptaufgabe darin besteht, eine interne Auflistung oder ein Array zu kapseln. Nehmen Sie beispielsweise an, Sie haben eine Klasse mit dem Namen TempRecord zur Darstellung der Temperatur zu 10 verschiedenen Zeitpunkten während eines 24-stündigen Zeitraums. Die Klasse enthält ein Array mit dem Namen "temps" und dem float-Datentyp zur Darstellung der Temperaturwerte sowie einen DateTime-Wert zur Darstellung der Zeitpunkte, zu denen die Temperaturen erfasst wurden. Durch die Implementierung eines Indexers in dieser Klasse können Clients auf die Temperaturwerte in einer TempRecord-Instanz als float temp = tr[4] statt als float temp = tr.temps[4] zugreifen. Durch die Angabe des Indexers wird nicht nur die Syntax für Clientanwendungen vereinfacht, die Klasse und ihr Zweck werden darüber hinaus für andere Entwickler verständlicher.
Um einen Indexer für eine Klasse oder eine Struktur zu deklarieren, verwenden Sie das this-Schlüsselwort wie in folgendem Beispiel:
public int this[int index] // Indexer declaration
{
// get and set accessors
}
Hinweise
Der Typ eines Indexers und der Typ seiner Parameter muss mindestens so gut zugänglich wie der Indexer selbst sein. Weitere Informationen über 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 mehr als einen Indexer in derselben Klasse deklarieren, müssen diese verschiedene Signaturen aufweisen.
Ein Indexerwert wird nicht als Variable klassifiziert. Daher ist es nicht möglich, einen Indexerwert als ref-Parameter oder als out-Parameter zu übergeben.
Verwenden Sie in der Deklaration ein name-Attribut, um dem Indexer einen Namen zu geben, den andere Sprachen verwenden können. Beispiel:
[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this [int index] // Indexer declaration
{
}
Dieser Indexer hat den Namen TheItem. Wird das Namensattribut nicht bereitgestellt, wird Item zum Standardnamen.
Beispiel 1
Beschreibung
Das folgende Beispiel veranschaulicht die Deklaration des private-Arrayfelds temps und eines Indexers. Mit dem Indexer ist ein direkter Zugriff auf die tempRecord[i]-Instanz möglich. Alternativ zum Indexer können Sie das Array als public-Member deklarieren und auf dessen Member tempRecord.temps[i] direkt zugreifen.
Beachten Sie, dass bei der Auswertung des Indexerzugriffs, z. B. in einer Console.Write-Anweisung, der get-Accessor aufgerufen wird. Wenn kein get-Accessor vorhanden ist, tritt daher während der Kompilierung ein Fehler 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();
}
}
Indizieren mit anderen Werten
C# beschränkt den Indextyp nicht auf eine ganze Zahl. Zum Beispiel kann es nützlich sein, eine Zeichenfolge mit einem Indexer zu verwenden. Ein solcher Indexer kann implementiert werden, indem in der Auflistung nach der Zeichenfolge gesucht und der richtige Wert zurückgegeben wird. Da Accessoren überladen werden können, können die Zeichenfolgenversion und die ganzzahlige 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 des Tages annimmt sowie den dazugehörigen ganzzahligen Wert zurückgibt. Zum Beispiel 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 - 1; 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:
Bauen Sie einen Code zur Fehlerbehandlung für den Fall ein, dass Clientcode in einem ungültigen Indexwert übergeben wird. Im ersten Beispiel in diesem Thema stellt die TempRecord-Klasse eine Length-Eigenschaft bereit, die eine Überprüfung der Eingabe durch den Clientcode vor Übergabe an den Indexer ermöglicht. Sie können den Fehlerbehandlungscode auch in den Indexer selbst einfügen. Dokumentieren Sie ausgelöste Ausnahmen in einem Indexeraccessor für Benutzer. Weitere Informationen finden Sie unter Entwurfsrichtlinien für Ausnahmen.
Schränken Sie den Zugriff des get-Accessors und des set-Accessors so ein, dass die Beschränkung angemessen ist. Insbesondere ist dies für den set-Accessor wichtig. Weitere Informationen hierzu finden Sie unter Asymmetrischer Accessorzugriff (C#-Programmierhandbuch).