Utiliser des indexeurs (Guide de programmation C#)Using indexers (C# Programming Guide)

Les indexeurs simplifient, d’un point de vue syntaxique, la création d’une classe, d’un struct ou d’une interface auxquels les applications clientes peuvent accéder exactement comme à un tableau.Indexers are a syntactic convenience that enable you to create a class, struct, or interface that client applications can access just as an array. Le plus souvent, les indexeurs sont implémentés dans les types dont l’objectif premier est d’encapsuler une collection ou un tableau interne.Indexers are most frequently implemented in types whose primary purpose is to encapsulate an internal collection or array. Prenons l’exemple d’une classe TempRecord qui représente la température, en Fahrenheit, enregistrée à 10 moments différents sur une période de 24 heures.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. Elle contient un tableau temps de type float[] pour stocker les valeurs de température.The class contains an array temps of type float[] to store the temperature values. En implémentant un indexeur dans cette classe, les clients peuvent accéder aux températures dans une instance TempRecord sous la forme float temp = tr[4] et non sous la forme 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 notation d’indexeur simplifie non seulement la syntaxe pour les applications clientes, mais elle permet également aux autres développeurs de comprendre de façon plus intuitive l’objectif de la classe.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.

Pour déclarer un indexeur sur une classe ou un struct, utilisez le mot clé this, comme dans l’exemple suivant :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  
}  

RemarquesRemarks

Le type d’un indexeur et le type de ses paramètres doivent être au moins aussi accessibles que l’indexeur lui-même.The type of an indexer and the type of its parameters must be at least as accessible as the indexer itself. Pour plus d’informations sur les niveaux d’accessibilité, consultez Modificateurs d’accès.For more information about accessibility levels, see Access Modifiers.

Pour plus d’informations sur l’utilisation d’indexeurs avec une interface, consultez Indexeurs d’interface.For more information about how to use indexers with an interface, see Interface Indexers.

La signature d’un indexeur est composée du nombre et des types de ses paramètres formels.The signature of an indexer consists of the number and types of its formal parameters. Elle ne comporte ni le type de l’indexeur ni le nom des paramètres formels.It doesn't include the indexer type or the names of the formal parameters. Si vous déclarez plusieurs indexeurs dans la même classe, ils doivent avoir des signatures différentes.If you declare more than one indexer in the same class, they must have different signatures.

Une valeur d’indexeur n’est pas classée comme variable ; vous ne pouvez donc pas la passer comme paramètre 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.

Pour affecter à l’indexeur un nom exploitable dans d’autres langages, utilisez System.Runtime.CompilerServices.IndexerNameAttribute, comme dans l’exemple suivant :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  
}  

Cet indexeur portera le nom TheItem.This indexer will have the name TheItem. Si vous ne précisez pas le nom de l’attribut, Item est utilisé comme nom par défaut.Not providing the name attribute would make Item the default name.

Exemple 1Example 1

L’exemple suivant montre comment déclarer un champ de tableau privé temps, et un indexeur.The following example shows how to declare a private array field, temps, and an indexer. L’indexeur permet d’accéder directement à l’instance tempRecord[i].The indexer enables direct access to the instance tempRecord[i]. Comme alternative à l’utilisation de l’indexeur, vous pouvez déclarer le tableau comme membre public et accéder directement à ses membres, 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.

Notez que quand l’accès à un indexeur est évalué, par exemple dans une instruction Console.Write, l’accesseur get est appelé.Notice that when an indexer's access is evaluated, for example, in a Console.Write statement, the get accessor is invoked. C’est pourquoi une erreur de compilation se produit s’il n’existe aucun accesseur get.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
    */

Indexation avec d’autres valeursIndexing using other values

C# ne limite pas le type de paramètre d’indexeur au type entier.C# doesn't limit the indexer parameter type to integer. Par exemple, il peut être utile d’utiliser une chaîne avec un indexeur.For example, it may be useful to use a string with an indexer. Il est possible d’implémenter un tel indexeur en recherchant la chaîne dans la collection et en retournant la valeur appropriée.Such an indexer might be implemented by searching for the string in the collection, and returning the appropriate value. Comme les accesseurs peuvent être surchargés, les versions chaîne et entier peuvent coexister.As accessors can be overloaded, the string and integer versions can co-exist.

Exemple 2Example 2

L’exemple suivant déclare une classe qui stocke les jours de la semaine.The following example declares a class that stores the days of the week. Un accesseur get prend une chaîne, le nom d’un jour, et retourne l’entier correspondant.A get accessor takes a string, the name of a day, and returns the corresponding integer. Par exemple, « Sunday » retourne 0, « Monday » retourne 1 et ainsi de suite.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

Programmation fiableRobust programming

La sécurité et la fiabilité des indexeurs peuvent être améliorées de deux manières principales :There are two main ways in which the security and reliability of indexers can be improved:

  • N’oubliez pas d’incorporer une stratégie de gestion des erreurs au cas où le code client passerait une valeur d’index non valide.Be sure to incorporate some type of error-handling strategy to handle the chance of client code passing in an invalid index value. Dans le premier exemple décrit plus haut dans cette rubrique, la classe TempRecord fournit une propriété Length qui permet au code client de vérifier l’entrée avant de la passer à l’indexeur.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. Vous pouvez également placer le code de gestion des erreurs à l’intérieur de l’indexeur lui-même.You can also put the error handling code inside the indexer itself. N’oubliez pas d’indiquer aux utilisateurs toutes les exceptions que vous levez dans un accesseur d’indexeur.Be sure to document for users any exceptions that you throw inside an indexer accessor.

  • Définissez pour les accesseurs get et set une accessibilité aussi restrictive que possible.Set the accessibility of the get and set accessors to be as restrictive as is reasonable. Cela est particulièrement important dans le cas de l’accesseur set.This is important for the set accessor in particular. Pour plus d’informations, consultez Restriction d’accessibilité de l’accesseur.For more information, see Restricting Accessor Accessibility.

Voir aussiSee also