Usando indexadores (Guia de Programação em C#)Using indexers (C# Programming Guide)

Os indexadores são uma conveniência sintática que permitem criar uma classe, struct ou interface que os aplicativos clientes podem acessar como uma matriz.Indexers are a syntactic convenience that enable you to create a class, struct, or interface that client applications can access just as an array. Os indexadores são implementados em tipos cuja principal finalidade é encapsular uma coleção ou matriz interna.Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array. Por exemplo, suponha que você tenha uma classe TempRecord que representa a temperatura em Fahrenheit, conforme registrada em 10 momentos diferentes durante um período de 24 horas.For example, suppose you have a class TempRecord that represents the temperature in Fahrenheit as recorded at 10 different times during a 24 hour period. A classe contém uma matriz temps do tipo float[] para armazenar os valores de temperatura.The class contains an array temps of type float[] to store the temperature values. Ao implementar um indexador nessa classe, os clientes podem acessar as temperaturas em uma instância TempRecord como float temp = tr[4], e não como float temp = tr.temps[4].By implementing an indexer in this class, clients can access the temperatures in a TempRecord instance as float temp = tr[4] instead of as float temp = tr.temps[4]. A notação do indexador não simplifica somente a sintaxe para aplicativos clientes; ela também torna a classe e sua finalidade mais intuitivas para que os outros desenvolvedores entendam.The indexer notation not only simplifies the syntax for client applications; it also makes the class and its purpose more intuitive for other developers to understand.

Para declarar um indexador em uma classe ou struct, use a palavra-chave this, como mostra o seguinte exemplo:To declare an indexer on a class or struct, use the this keyword, as the following example shows:

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

ComentáriosRemarks

O tipo de um indexador e o tipo dos seus parâmetros devem ser pelo menos tão acessíveis quanto o próprio indexador.The type of an indexer and the type of its parameters must be at least as accessible as the indexer itself. Para obter mais informações sobre níveis de acessibilidade, consulte Modificadores de acesso.For more information about accessibility levels, see Access Modifiers.

Para obter mais informações sobre como usar indexadores com uma interface, consulte Indexadores de Interface.For more information about how to use indexers with an interface, see Interface Indexers.

A assinatura de um indexador consiste do número e dos tipos de seus parâmetros formais.The signature of an indexer consists of the number and types of its formal parameters. Ela não inclui o tipo de indexador nem os nomes dos parâmetros formais.It doesn't include the indexer type or the names of the formal parameters. Se você declarar mais de um indexador na mesma classe, eles terão diferentes assinaturas.If you declare more than one indexer in the same class, they must have different signatures.

Um valor de indexador não é classificado como uma variável; portanto, não é possível passar um valor de indexador como um parâmetro ref ou out.An indexer value is not classified as a variable; therefore, you cannot pass an indexer value as a ref or out parameter.

Para fornecer o indexador com um nome que outras linguagens possam usar, use System.Runtime.CompilerServices.IndexerNameAttribute, como mostra o seguinte exemplo:To provide the indexer with a name that other languages can use, use System.Runtime.CompilerServices.IndexerNameAttribute, as the following example shows:

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

Este indexador terá o nome TheItem.This indexer will have the name TheItem. Não fornecer o atributo de nome tornaria Item o nome padrão.Not providing the name attribute would make Item the default name.

Exemplo 1Example 1

O exemplo a seguir mostra como declarar um campo de matriz privada, temps e um indexador.The following example shows how to declare a private array field, temps, and an indexer. O indexador permite acesso direto à instância tempRecord[i].The indexer enables direct access to the instance tempRecord[i]. A alternativa ao uso do indexador é declarar a matriz como um membro público e acessar seus membros, tempRecord.temps[i], diretamente.The alternative to using the indexer is to declare the array as a public member and access its members, tempRecord.temps[i], directly.

Observe que, quando o acesso de um indexador é avaliado, por exemplo, em uma instrução Console.Write, o acessador get é invocado.Notice that when an indexer's access is evaluated, for example, in a Console.Write statement, the get accessor is invoked. Portanto, se não existir nenhum acessador get, ocorrerá um erro em tempo de compilação.Therefore, if no get accessor exists, a compile-time error occurs.

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

Indexando usando outros valoresIndexing using other values

O C# não limita o tipo de parâmetro do indexador ao inteiro.C# doesn't limit the indexer parameter type to integer. Por exemplo, talvez seja útil usar uma cadeia de caracteres com um indexador.For example, it may be useful to use a string with an indexer. Esse indexador pode ser implementado pesquisando a cadeia de caracteres na coleção e retornando o valor adequado.Such an indexer might be implemented by searching for the string in the collection, and returning the appropriate value. Como os acessadores podem ser sobrecarregados, as versões do inteiro e da cadeia de caracteres podem coexistir.As accessors can be overloaded, the string and integer versions can co-exist.

Exemplo 2Example 2

O exemplo a seguir declara uma classe que armazena os dias da semana.The following example declares a class that stores the days of the week. Um acessador get aceita uma cadeia de caracteres, o nome de um dia e retorna o inteiro correspondente.A get accessor takes a string, the name of a day, and returns the corresponding integer. Por exemplo, "Sunday" retorna 0, "Monday" retorna 1 e assim por diante.For example, "Sunday" returns 0, "Monday" returns 1, and so on.

// 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 an Exception if the day is not found
    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 robustaRobust programming

Há duas maneiras principais nas quais a segurança e a confiabilidade de indexadores podem ser melhoradas:There are two main ways in which the security and reliability of indexers can be improved:

  • Certifique-se de incorporar algum tipo de estratégia de tratamento de erros para manipular a chance de passagem de código cliente em um valor de índice inválido.Be sure to incorporate some type of error-handling strategy to handle the chance of client code passing in an invalid index value. Anteriormente, no primeiro exemplo neste tópico, a classe TempRecord oferece uma propriedade Length que permite que o código cliente verifique a saída antes de passá-la para o indexador.In the first example earlier in this topic, the TempRecord class provides a Length property that enables the client code to verify the input before passing it to the indexer. Também é possível colocador o código de tratamento de erro dentro do próprio indexador.You can also put the error handling code inside the indexer itself. Certifique-se documentar para os usuários as exceções que você gera dentro de um acessador do indexador.Be sure to document for users any exceptions that you throw inside an indexer accessor.

  • Defina a acessibilidade dos acessadores get e set para que ela seja mais restritiva possível.Set the accessibility of the get and set accessors to be as restrictive as is reasonable. Isso é importante para o acessador set em particular.This is important for the set accessor in particular. Para obter mais informações, consulte Restringindo a acessibilidade aos acessadores.For more information, see Restricting Accessor Accessibility.

Consulte tambémSee also