Uso de indizadores (Guía de programación de C#)Using indexers (C# Programming Guide)

Los indexadores son una comodidad sintáctica que le permiten crear una clase, un struct o una interfaz a los que pueden acceder las aplicaciones cliente simplemente como una 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. Los indexadores se implementan con más frecuencia en tipos cuyo propósito principal consiste en encapsular una matriz o colección interna.Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array. Por ejemplo, suponga que tiene una clase TempRecord que representa la temperatura en grados Fahrenheit que se registra en 10 momentos diferentes durante un 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. La clase contiene una matriz temps de tipo float[] para almacenar los valores de temperatura.The class contains an array temps of type float[] to store the temperature values. Si implementa un indizador en esta clase, los clientes pueden tener acceso a las temperaturas en una instancia de TempRecord como float temp = tr[4] en lugar de 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]. La notación del indexador no solo simplifica la sintaxis para las aplicaciones cliente; también hace que la clase y su finalidad sean más intuitivas para que las conozcan otros desarrolladores.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 un indizador en una clase o un struct, use la palabra clave this, como en este ejemplo: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  
}  

ComentariosRemarks

Los tipos de un indexador y de sus parámetros deben ser al menos igual de accesibles que el propio indexador.The type of an indexer and the type of its parameters must be at least as accessible as the indexer itself. Para obtener más información sobre los niveles de accesibilidad, vea Modificadores de acceso.For more information about accessibility levels, see Access Modifiers.

Para obtener más información sobre cómo usar los indexadores con una interfaz, vea Indizadores en interfaces.For more information about how to use indexers with an interface, see Interface Indexers.

La firma de un indexador consta del número y los tipos de sus parámetros formales.The signature of an indexer consists of the number and types of its formal parameters. No incluye el tipo de indizador ni los nombres de los parámetros formales.It doesn't include the indexer type or the names of the formal parameters. Si declara más de un indexador en la misma clase, deben tener firmas diferentes.If you declare more than one indexer in the same class, they must have different signatures.

Un valor de indexador no está clasificado como una variable; por tanto, no se puede pasar un valor de indexador como un parámetro ref u out.An indexer value is not classified as a variable; therefore, you cannot pass an indexer value as a ref or out parameter.

Para proporcionar el indizador con un nombre que puedan usar otros lenguajes, use System.Runtime.CompilerServices.IndexerNameAttribute, como se muestra en el ejemplo siguiente: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 tendrá el nombre TheItem.This indexer will have the name TheItem. Si no se proporciona el atributo de nombre, Item será el nombre predeterminado.Not providing the name attribute would make Item the default name.

Ejemplo 1Example 1

En el ejemplo siguiente, se muestra cómo declarar un campo de matriz privada, temps, como un indexador.The following example shows how to declare a private array field, temps, and an indexer. El indexador permite el acceso directo a la instancia tempRecord[i].The indexer enables direct access to the instance tempRecord[i]. La alternativa a usar el indexador es declarar la matriz como un miembro public y tener acceso directamente a sus miembros tempRecord.temps[i].The alternative to using the indexer is to declare the array as a public member and access its members, tempRecord.temps[i], directly.

Tenga en cuenta que, cuando se evalúa el acceso de un indexador (por ejemplo, en una instrucción Console.Write), se invoca al descriptor de acceso get.Notice that when an indexer's access is evaluated, for example, in a Console.Write statement, the get accessor is invoked. Por tanto, si no hay ningún descriptor de acceso get, se produce un error en tiempo de compilación.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
    */

Indexación con otros valoresIndexing using other values

C# no limita el tipo de parámetro indizador a un entero.C# doesn't limit the indexer parameter type to integer. Por ejemplo, puede ser útil usar una cadena con un indexador.For example, it may be useful to use a string with an indexer. Este tipo de indexador podría implementarse al buscar la cadena de la colección y devolver el valor adecuado.Such an indexer might be implemented by searching for the string in the collection, and returning the appropriate value. Ya que los descriptores de acceso se pueden sobrecargar, las versiones de cadena y entero pueden coexistir.As accessors can be overloaded, the string and integer versions can co-exist.

Ejemplo 2Example 2

En el ejemplo siguiente se declara una clase que almacena los días de la semana.The following example declares a class that stores the days of the week. Un descriptor de acceso get toma una cadena, el nombre de un día, y devuelve el entero correspondiente.A get accessor takes a string, the name of a day, and returns the corresponding integer. Por ejemplo, "Sunday" devuelve 0, "Monday" devuelve 1 y así sucesivamente.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

Programación sólidaRobust programming

Hay dos formas principales en que se pueden mejorar la seguridad y confiabilidad de los indexadores:There are two main ways in which the security and reliability of indexers can be improved:

  • Asegúrese de incorporar algún tipo de estrategia de control de errores para controlar la posibilidad de que el código de cliente pase un valor de índice no válido.Be sure to incorporate some type of error-handling strategy to handle the chance of client code passing in an invalid index value. En el primer ejemplo de este tema, la clase TempRecord proporciona una propiedad Length que permite al código de cliente comprobar la entrada antes de pasarla al 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. También puede colocar el código de control de errores en el propio indexador.You can also put the error handling code inside the indexer itself. Asegúrese de documentar para los usuarios cualquier excepción que se produzca dentro de un descriptor de acceso del indexador.Be sure to document for users any exceptions that you throw inside an indexer accessor.

  • Establezca la accesibilidad de los descriptores de acceso get and set para que sea tan restrictiva como razonable.Set the accessibility of the get and set accessors to be as restrictive as is reasonable. Esto es importante para el descriptor de acceso set en particular.This is important for the set accessor in particular. Para más información, vea Restringir la accesibilidad del descriptor de acceso.For more information, see Restricting Accessor Accessibility.

Vea tambiénSee also