Usando indexadores (Guia de Programação em C#)

Os indexadores são uma conveniência sintática que permitem que você criar um classe, struct, ou interface que os aplicativos cliente podem acessar apenas como uma matriz. Indexadores são mais frequentemente implementados em tipos cujo objetivo principal é encapsular uma coleção interna ou array. Por exemplo, suponha que você tenha uma classe chamada TempRecord que representa a temperatura em Farenheit gravada 10 vezes diferentes durante um período de 24 horas. A classe contém uma matriz chamada "temps" de tipo flutuante para representar as temperaturas e um DateTime que representa a data em que as temperaturas foram registradas. Implementando um indexador nesta classe, os clientes podem acessar as temperaturas em uma instância de TempRecord como float temp = tr[4] em vez de como float temp = tr.temps[4]. A notação do indexador não apenas simplifica a sintaxe para aplicativos do cliente. Ele também torna a classe e sua finalidade mais intuitiva para outros desenvolvedores entender.

Para declarar um indexador em uma classe ou struct, use o Este palavra-chave, como no exemplo:

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

Comentários

O tipo de um 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 os níveis de acessibilidade, consulte Modificadores de acesso.

Para obter mais informações sobre como usar indexadores com uma interface, consulte Interface indexadores.

A assinatura de um indexador consiste do número e tipos de seus parâmetros formais. Isso não inclui o tipo de indexador ou os nomes dos parâmetros formais. Se você declarar mais do que um indexador na mesma classe, eles devem ter diferentes assinaturas.

Um valor do indexador não é classificado como uma variável; Portanto, você não pode passar um valor de indexador como um ref ou check-out parâmetro.

Para fornecer um nome que outras linguagens podem usar o indexador, use um name atributo na declaração. Por exemplo:

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

Este indexador terá o nome TheItem. Não está fornecendo o atributo name tornaria Item o nome padrão.

Exemplo 1

Descrição

O exemplo a seguir mostra como declarar um campo particular do array, tempse um indexador. O indexador permite acesso direto à ocorrência de tempRecord[i]. Uma alternativa ao uso do indexador é declarar a matriz como uma pública membro e acessar seus membros, tempRecord.temps[i], diretamente.

Observe que, quando o acesso de um indexador é avaliado, por exemplo, em um Console.Write instrução, o obter acessador é invocado. Portanto, se nenhum get acessador existe, ocorrerá um erro em tempo de compilação.

Código

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
    */

Usando outros valores de indexação

C# não limita o tipo do indexador a um inteiro. Por exemplo, pode ser útil usar um string com um indexador. Tal indexador pode ser implementado pesquisando a string na coleção, e retornando o valor apropriado. Como os accessores podem ser sobrecarregados, as versões string e inteiros pode coexistirem.

Exemplo 2

Descrição

Neste exemplo, uma classe é declarada que armazena os dias da semana. A get o acessador é declarado que leva uma seqüência de caracteres, o nome de um dia e retorna o inteiro correspondente. Por exemplo, Domingo irá retornar 0, Segunda irá retornar 1, e assim sucessivamente.

Código

// 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

Programação robusta

Há duas formas principais em que a segurança e a confiabilidade dos indexadores podem ser melhoradas:

  • Certfique-se que algum tipo de estratégia de tratamento de erro seja incorporado para tratar a chance do código cliente passar um valor de índice inválido. No primeiro exemplo neste tópico, a classe TempRecord fornece uma propriedade Length que permite o código do cliente verificar a entrada antes de passá-la para o indexador. Você pode também colocar o código de tratamento de erro dentro do próprio indexador. Certifique-se que qualquer exceção que você lançar dentro de um accessor de indexador seja documentada para usuários.

  • Definir a acessibilidade da get e set acessadores para serem os mais restritivos é razoável. Isso é importante para o set acessador em particular. Para obter mais informações, consulte Restringindo a acessibilidade aos acessadores (Guia de Programação em C#).

Consulte também

Referência

Indexadores (Guia de Programação em C#)

Propriedades (Guia de Programação em C#)

Conceitos

Guia de Programação em C#