Indexeerfuncties gebruiken (C#-programmeerhandleiding)
Indexeerfuncties zijn een syntactisch gemak waarmee u een klasse, struct of interface kunt maken waartoe clienttoepassingen toegang hebben als een matrix. De compiler genereert een Item
eigenschap (of een alternatieve benoemde eigenschap indien IndexerNameAttribute aanwezig) en de juiste toegangsmethoden. Indexeerfuncties worden het vaakst geïmplementeerd in typen waarvan het primaire doel is om een interne verzameling of matrix in te kapselen. Stel dat u een klasse TempRecord
hebt die de temperatuur in Fahrenheit vertegenwoordigt, zoals vastgelegd op 10 verschillende tijden gedurende een periode van 24 uur. De klasse bevat een temps
matrix van het type float[]
om de temperatuurwaarden op te slaan. Door een indexeerfunctie in deze klasse te implementeren, hebben clients toegang tot de temperaturen in een TempRecord
exemplaar als float temp = tempRecord[4]
in plaats van als float temp = tempRecord.temps[4]
. De indexeerfunctie notatie vereenvoudigt niet alleen de syntaxis voor clienttoepassingen; het maakt de klasse en het doel ervan ook intuïtiever voor andere ontwikkelaars om te begrijpen.
Als u een indexeerfunctie voor een klasse of struct wilt declareren, gebruikt u dit trefwoord, zoals in het volgende voorbeeld wordt weergegeven:
// Indexer declaration
public int this[int index]
{
// get and set accessors
}
Belangrijk
Als u een indexeerfunctie declareren, wordt automatisch een eigenschap gegenereerd met de naam van Item
het object. De Item
eigenschap is niet rechtstreeks toegankelijk vanuit de toegangsexpressie van het exemplaarlid. Als u bovendien uw eigen Item
eigenschap toevoegt aan een object met een indexeerfunctie, krijgt u een cs0102-compilerfout. Als u deze fout wilt voorkomen, gebruikt u de IndexerNameAttribute naam van de indexeerfunctie, zoals verderop in dit artikel wordt beschreven.
Opmerkingen
Het type indexeerfunctie en het type van de parameters moeten ten minste zo toegankelijk zijn als de indexeerfunctie zelf. Zie Toegangsmodifiers voor meer informatie over toegankelijkheidsniveaus.
Zie Interface-indexeerfuncties voor meer informatie over het gebruik van indexeerfuncties met een interface.
De handtekening van een indexeerfunctie bestaat uit het aantal en de typen van de formele parameters. Het bevat niet het type indexeerfunctie of de namen van de formele parameters. Als u meer dan één indexeerfunctie in dezelfde klasse declareert, moeten ze verschillende handtekeningen hebben.
Een indexeerfunctie wordt niet geclassificeerd als een variabele; Daarom kan een indexeerfunctiewaarde niet worden doorgegeven door verwijzing (als een ref
of out
parameter), tenzij de waarde een verwijzing is (dat wil gezegd, wordt deze geretourneerd door verwijzing.)
Als u de indexeerfunctie een naam wilt opgeven die andere talen kunnen gebruiken, gebruikt System.Runtime.CompilerServices.IndexerNameAttributeu deze, zoals in het volgende voorbeeld wordt weergegeven:
// Indexer declaration
[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this[int index]
{
// get and set accessors
}
Deze indexeerfunctie heeft de naam TheItem
, omdat deze wordt overschreven door het kenmerk naam van de indexeerfunctie. Standaard is Item
de naam van de indexeerfunctie.
Voorbeeld 1
In het volgende voorbeeld ziet u hoe u een privématrixveld temps
en een indexeerfunctie declareert. De indexeerfunctie maakt directe toegang tot het exemplaar tempRecord[i]
mogelijk. Het alternatief voor het gebruik van de indexeerfunctie is om de matrix rechtstreeks als openbaar lid te declareren en toegang te krijgen tot de leden 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;
}
}
U ziet dat wanneer de toegang van een indexeerfunctie wordt geëvalueerd, bijvoorbeeld in een Console.Write
instructie, de get accessor wordt aangeroepen. Als er geen get
accessor bestaat, treedt er daarom een compilatietijdfout op.
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]}");
}
Indexeren met behulp van andere waarden
C# beperkt het parametertype indexeerfunctie niet tot geheel getal. Het kan bijvoorbeeld handig zijn om een tekenreeks met een indexeerfunctie te gebruiken. Een dergelijke indexeerfunctie kan worden geïmplementeerd door te zoeken naar de tekenreeks in de verzameling en de juiste waarde te retourneren. Omdat accessors kunnen worden overbelast, kunnen de tekenreeks- en gehele getallen naast elkaar bestaan.
Voorbeeld 2
In het volgende voorbeeld wordt een klasse aangegeven waarin de dagen van de week worden opgeslagen. Een get
accessor neemt een tekenreeks, de naam van een dag en retourneert het bijbehorende gehele getal. 'Zondag' retourneert bijvoorbeeld 0, 'maandag' retourneert 1, enzovoort.
// 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");
}
}
Voorbeeld 2 gebruiken
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}");
}
Voorbeeld 3
In het volgende voorbeeld wordt een klasse declareren waarin de dagen van de week worden opgeslagen met behulp van de System.DayOfWeek enum. Een get
accessor neemt een DayOfWeek
, de waarde van een dag en retourneert het bijbehorende gehele getal. Retourneert bijvoorbeeld DayOfWeek.Sunday
0, DayOfWeek.Monday
retourneert 1, enzovoort.
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.");
}
}
Voorbeeld 3 gebruiken
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}");
}
Robuuste programmering
Er zijn twee belangrijke manieren waarop de beveiliging en betrouwbaarheid van indexeerfuncties kunnen worden verbeterd:
Zorg ervoor dat u een type strategie voor foutafhandeling opneemt om de kans op het doorgeven van clientcode in een ongeldige indexwaarde af te handelen. In het eerste voorbeeld eerder in dit artikel bevat de klasse TempRecord een eigenschap Length waarmee de clientcode de invoer kan verifiëren voordat deze aan de indexeerfunctie wordt doorgegeven. U kunt ook de foutcode in de indexeerfunctie zelf plaatsen. Zorg ervoor dat u documenteer voor gebruikers eventuele uitzonderingen die u in een toegangsfunctie voor een indexeerfunctie genereert.
Stel de toegankelijkheid van de get - en set-accessors zo beperkend in als redelijk. Dit is met name belangrijk voor de
set
toegangsverantwoordelijke. Zie Toegankelijkheid van accessor beperken voor meer informatie.