80 votes

Pourquoi C# n'implémente-t-il pas les propriétés indexées?

Je sais, je sais... La réponse d'Eric Lippert à ce genre de question est généralement quelque chose du genre "parce que cela ne valait pas la peine de le concevoir, implémenter, tester et le documenter".

Mais quand même, j'aimerais une meilleure explication... Je lisais ce billet de blog sur les nouvelles fonctionnalités de C# 4, et dans la section sur COM Interop, la partie suivante a attiré mon attention :

En passant, ce code utilise une nouvelle fonctionnalité de plus : les propriétés indexées (jetez un œil aux crochets après Range.) Mais cette fonctionnalité est disponible uniquement pour COM interop ; vous ne pouvez pas créer vos propres propriétés indexées en C# 4.0.

D'accord, mais pourquoi ? Je savais déjà et regrettait qu'il n'était pas possible de créer des propriétés indexées en C#, mais cette phrase m'a fait réfléchir à nouveau. Je vois plusieurs bonnes raisons de l'implémenter :

  • le CLR le prend en charge (par exemple, PropertyInfo.GetValue a un paramètre index), c'est donc dommage de ne pas pouvoir en profiter en C#
  • il est pris en charge pour COM Interop, comme le montre l'article (en utilisant la dispatch dynamique)
  • il est implémenté dans VB.NET
  • il est déjà possible de créer des indexeurs, c'est-à-dire d'appliquer un index à l'objet lui-même, donc ce ne serait probablement pas compliqué d'étendre l'idée aux propriétés, en conservant la même syntaxe et en remplaçant simplement this par un nom de propriété

Cela permettrait d'écrire ce genre de choses :

public class Foo
{
    private string[] _values = new string[3];
    public string Values[int index]
    {
        get { return _values[index]; }
        set { _values[index] = value; }
    }
}

Actuellement, la seule solution de contournement que je connais est de créer une classe interne (ValuesCollection par exemple) qui implémente un indexeur, et de modifier la propriété Values pour qu'elle renvoie une instance de cette classe interne.

C'est très facile à faire, mais ennuyeux... Donc peut-être que le compilateur pourrait le faire pour nous ! Une option serait de générer une classe interne qui implémente l'indexeur, et de l'exposer via une interface générique publique :

// interface définie dans l'espace de noms System
public interface IIndexer
{
    TValue this[TIndex index]  { get; set; }
}

public class Foo
{
    private string[] _values = new string[3];

    private class <>c__DisplayClass1 : IIndexer
    {
        private Foo _foo;
        public <>c__DisplayClass1(Foo foo)
        {
            _foo = foo;
        }

        public string this[int index]
        {
            get { return _foo._values[index]; }
            set { _foo._values[index] = value; }
        }
    }

    private IIndexer <>f__valuesIndexer;
    public IIndexer Values
    {
        get
        {
            if (<>f__valuesIndexer == null)
                <>f__valuesIndexer = new <>c__DisplayClass1(this);
            return <>f__valuesIndexer;
        }
    }
}

Mais bien sûr, dans ce cas, la propriété retournerait en fait un IIndexer, et ne serait pas vraiment une propriété indexée... Il serait préférable de générer une véritable propriété indexée CLR.

Qu'en pensez-vous ? Aimeriez-vous voir cette fonctionnalité en C# ? Sinon, pourquoi ?

113voto

Eric Lippert Points 300275

Voici comment nous avons conçu C# 4.

Tout d'abord, nous avons dressé une liste de toutes les fonctionnalités possibles que nous pourrions ajouter au langage.

Ensuite, nous avons regroupé les fonctionnalités en "cela est mauvais, nous ne devons jamais le faire", "cela est génial, nous devons le faire" et "cela est bien mais ne le faisons pas cette fois-ci".

Ensuite, nous avons examiné quel était notre budget pour concevoir, implémenter, tester, documenter, livrer et maintenir les fonctionnalités "indispensables" et avons découvert que nous dépassions le budget de 100%.

Nous avons donc déplacé un tas de choses du groupe "indispensable" au groupe "agréable à avoir".

Les propriétés indexées n'ont jamais été en haut de la liste des "fonctionnalités indispensables". Elles sont très bas sur la liste "agréable" et flirtent avec la liste "mauvaise idée".

Chaque minute passée à concevoir, implémenter, tester, documenter ou maintenir une fonctionnalité agréable X est une minute que nous ne pouvons pas consacrer aux fonctionnalités extraordinaires A, B, C, D, E, F et G. Nous devons hiérarchiser de manière impitoyable afin de ne réaliser que les fonctionnalités les meilleures possibles. Les propriétés indexées seraient agréables, mais agréable n'est même pas suffisant pour être réellement implémentées.

19voto

Pavel Minaev Points 60647

Un indexeur C# est une propriété indexée. Il est nommé Item par défaut (et vous pouvez vous y référer ainsi par exemple en VB), et vous pouvez le modifier avec IndexerNameAttribute si vous le souhaitez.

Je ne suis pas sûr pourquoi, plus précisément, il a été conçu de cette manière, mais cela semble être une limitation intentionnelle. Cependant, cela est conforme aux directives de conception de Framework, qui recommandent l'approche d'une propriété non indexée renvoyant un objet indexable pour les collections de membres. Autrement dit, "être indexable" est une caractéristique d'un type ; s'il est indexable de plus d'une façon, alors il devrait vraiment être divisé en plusieurs types.

14voto

Ion Todirel Points 1731

Parce que vous pouvez déjà le faire un peu, et cela vous a obligé à penser en termes d'OO, l'ajout de propriétés indexées ne ferait qu'ajouter plus de bruit au langage. Et juste une autre façon de faire une autre chose.

class Foo
{
    public Values Values { ... }
}

class Values
{
    public string this[int index] { ... }    
}

foo.Values[0]

Personnellement, je préférerais voir une seule façon de faire quelque chose, plutôt que 10 façons. Mais bien sûr, c'est un avis subjectif.

8voto

J'avais l'habitude de favoriser l'idée des propriétés indexées mais j'ai ensuite réalisé que cela ajouterait une horrible ambiguïté et en fait découragerait la fonctionnalité. Les propriétés indexées signifieraient que vous n'avez pas une instance de collection enfant. C'est à la fois bien et mal. C'est moins embêtant à implémenter et vous n'avez pas besoin d'une référence à la classe propriétaire. Mais cela signifie aussi que vous ne pouvez pas passer cette collection enfant à quoi que ce soit; vous devriez probablement l'énumérer à chaque fois. Et vous ne pouvez pas faire un foreach dessus. Le pire de tout, vous ne pouvez pas dire en regardant une propriété indexée si c'est cela ou une propriété de collection.

L'idée est rationnelle mais elle conduit simplement à de l'inflexibilité et à de la gêne abrupte.

2voto

cdiggins Points 5549

Une autre solution consiste à consulter Création facile de propriétés prenant en charge l'indexation en C#, qui nécessite moins de travail.

ÉDITER: Je devrais également ajouter que en réponse à la question initiale, si nous pouvons atteindre la syntaxe souhaitée, avec le support de bibliothèque, alors je pense qu'il doit y avoir un argument très solide pour l'ajouter directement au langage, afin de minimiser le gonflement du langage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X