Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Os indexadores são uma conveniência sintática que permite criar uma classe, struct ou interface que os aplicativos cliente podem acessar como uma matriz. O compilador gera uma Item propriedade (ou uma propriedade com nome alternativo, se IndexerNameAttribute estiver presente) e os métodos de acesso apropriados. Os indexadores são mais frequentemente implementados em tipos cuja finalidade principal é encapsular uma coleção ou matriz interna. Por exemplo, suponha que você tenha uma classe TempRecord que represente a temperatura em Fahrenheit registrada em 10 momentos diferentes durante um período de 24 horas. A classe contém uma temps matriz de tipo float[] para armazenar os valores de temperatura. Ao implementar um indexador nessa classe, os clientes podem acessar as temperaturas em uma TempRecord instância como float temp = tempRecord[4] em vez de como float temp = tempRecord.temps[4]. A notação do indexador não apenas simplifica a sintaxe para aplicativos cliente; Isso também torna a classe e seu propósito mais intuitivos para outros desenvolvedores entenderem.
Para declarar um indexador em uma classe ou struct, use a palavra-chave this , como mostra o exemplo a seguir:
// Indexer declaration
public int this[int index]
{
// get and set accessors
}
Importante
Declarar um indexador gerará automaticamente uma propriedade nomeada Item no objeto. A Item propriedade não é diretamente acessível a partir da expressão de acesso do membro da instância. Além disso, se você adicionar sua própria Item propriedade a um objeto com um indexador, obterá um erro de compilador CS0102. Para evitar esse erro, use o IndexerNameAttribute renomear o indexador conforme detalhado mais adiante neste artigo.
Observações
O tipo de indexador e o tipo de seus parâmetros devem ser pelo menos tão acessíveis quanto o próprio indexador. Para obter mais informações sobre níveis de acessibilidade, consulte Modificadores de acesso.
Para obter mais informações sobre como usar indexadores com uma interface, consulte Indexadores de interface.
A assinatura de um indexador consiste no número e tipos de seus parâmetros formais. Ele não inclui o tipo de indexador ou os nomes dos parâmetros formais. Se você declarar mais de um indexador na mesma classe, eles deverão ter assinaturas diferentes.
Um indexador não é classificado como uma variável; Portanto, um valor de indexador não pode ser passado por referência (como um ref parâmetro OR out ), a menos que seu valor seja uma referência (ou seja, ele retorna por referência).
Para fornecer ao indexador um nome que outros idiomas possam usar, use System.Runtime.CompilerServices.IndexerNameAttribute, como mostra o exemplo a seguir:
// Indexer declaration
[System.Runtime.CompilerServices.IndexerName("TheItem")]
public int this[int index]
{
// get and set accessors
}
Este indexador tem o nome TheItem, pois é substituído pelo atributo de nome do indexador. Por padrão, o nome do indexador é Item.
Exemplo 1
O exemplo a seguir mostra como declarar um campo de matriz privada, tempse um indexador. O indexador permite o acesso direto à instância tempRecord[i]. A alternativa ao uso do indexador é declarar a matriz como um membro público e acessar seus membros, tempRecord.temps[i]diretamente.
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;
}
}
Observe que quando o acesso de um indexador é avaliado, por exemplo, em uma Console.Write instrução, o acessador get é invocado. Portanto, se nenhum get acessador existir, ocorrerá um erro em tempo de compilação.
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]}");
}
Indexação usando outros valores
O C# não limita o tipo de parâmetro do indexador a inteiro. Por exemplo, pode ser útil usar uma cadeia de caracteres com um indexador. Esse indexador pode ser implementado pesquisando a cadeia de caracteres na coleção e retornando o valor apropriado. Como os acessadores podem ser sobrecarregados, as versões string e inteiro podem coexistir.
Exemplo 2
O exemplo a seguir declara uma classe que armazena os dias da semana. Um get acessador usa uma cadeia de caracteres, o nome de um dia, e retorna o inteiro correspondente. Por exemplo, "Domingo" retorna 0, "Segunda-feira" retorna 1 e assim por diante.
// 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");
}
}
Exemplo de consumo 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}");
}
Exemplo 3
O exemplo a seguir declara uma classe que armazena os dias da semana usando o System.DayOfWeek enum. Um get acessador usa um DayOfWeek, o valor de um dia e retorna o número inteiro correspondente. Por exemplo, DayOfWeek.Sunday retorna 0, DayOfWeek.Monday retorna 1 e assim por diante.
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.");
}
}
Exemplo de consumo 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}");
}
Programação robusta
Existem duas formas principais de melhorar a segurança e a fiabilidade dos indexadores:
Certifique-se de incorporar algum tipo de estratégia de tratamento de erros para lidar com a chance de o código do cliente passar em um valor de índice inválido. No primeiro exemplo anterior neste artigo, a classe TempRecord fornece uma propriedade Length que permite que o código do cliente verifique a entrada antes de passá-la para o indexador. Você também pode colocar o código de tratamento de erros dentro do próprio indexador. Certifique-se de documentar para os usuários quaisquer exceções que você lançar dentro de um acessador indexador.
Defina a acessibilidade dos acessadores get e set para ser tão restritiva quanto razoável. Isto é importante para o
setacessor em particular. Para obter mais informações, consulte Restringindo a acessibilidade do Accessor.