108 votes

Pourquoi IList ne prend-il pas en charge AddRange

List.AddRange() existe, mais IList.AddRange() n'existe pas.
Cela me semble étrange. Quelle est la raison derrière cela?

74voto

xanatos Points 30513

Parce qu'une interface doit être facile à implémenter et ne pas contenir "tout sauf la cuisine". Si vous ajoutez AddRange vous devriez alors ajouter InsertRange et RemoveRange (pour la symétrie). Une meilleure question serait pourquoi il n'y a pas de méthodes d'extension pour l'interface IList similaire à l'interface IEnumerable. (les méthodes d'extension pour Sort en place, BinarySearch, ... seraient utiles)

18voto

Emilien Mathieu Points 216

Pour ceux qui veulent avoir des méthodes d'extension pour "AddRange", "Sort", ... sur IList,

Voici la méthode d'extension AddRange:

 public static void AddRange(this IList source, IEnumerable newList)
 {
     if (source == null)
     {
        throw new ArgumentNullException(nameof(source));
     }

     if (newList == null)
     {
        throw new ArgumentNullException(nameof(newList));
     }

     if (source is List concreteList)
     {
        concreteList.AddRange(newList);
        return;
     }

     foreach (var element in newList)
     {
        source.Add(element);
     }
}

J'ai créé une petite bibliothèque qui fait cela. Je trouve cela plus pratique que de devoir refaire ses méthodes d'extension sur chaque projet.

Certaines méthodes sont plus lentes que List mais elles font le travail.

Voici le lien GitHub pour les intéresser:

Dépôt IListExtension

3voto

Nikolay Points 117

En fait, personne, sauf les développeurs et architectes de la plateforme .Net, ne peut répondre à cette question. Mais il y a quelques points qui pourraient être des raisons.

Dans cette réponse, je parlerai de classes non génériques, mais presque tous mes mots seront également corrects pour les classes génériques.

Avant que je passe à l'explication, j'aimerais mentionner pour ceux qui ne le savent pas, que List<> et toutes les implémentations d'IList ne sont pas censées être une Liste en termes de programmation et de structures de données communes, cela signifie généralement liste chaînée. Et dans la documentation Microsoft de IList, nous pouvons voir la définition :

Représente une collection d'objets qui peuvent être accédés individuellement par index.

Donc, généralement, en lisant cette définition, vous ne devriez pas avoir de question sur "Pourquoi AddRange n'est pas présenté dans IList", mais "Pourquoi Add est présenté?". Et, en parlant de Add, il n'est pas dans l'interface IList, mais dans l'interface ICollection. Et c'est une chose vraiment étrange. Pourquoi? Parce que presque toutes les collections dans le .Net Standard héritent de ICollection. Et en raison de cela, il y a beaucoup d'endroits dans le code source .Net, où nous pouvons voir l'implémentation de Add comme dans la classe Array (Oui, Array implémente également IList) :

int IList.Add(Object value)
{
   throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
}

Il y a plus de choses que je pourrais dire sur les relations entre les interfaces de collections en C# (aussi sur IReadOnlyList, qui a été ajouté bien après IList et ressemble à une chose que IList était censé être). Mais je pense qu'il y a assez de contexte, et nous pouvons commencer à parler des raisons concrètes pour lesquelles IList n'a pas de AddRange, mais List<> en a.

  • Toutes les implémentations d'IList ne sont pas censées avoir une méthode AddRange.

    Comme je l'ai mentionné ci-dessus, il y a un problème avec la méthode Add. Beaucoup de collections en C# l'ont en fait, mais lèvent une NotSupportedException lorsqu'elle est appelée. Et la même situation (voire pire) se produirait avec la méthode AddRange. Donc seul List<> a besoin de cette méthode, mais toutes les autres implémentations d'IList n'en ont pas besoin. De plus, ces développeurs qui décident de créer leur propre implémentation d'IList devront implémenter AddRange, ce qui ne semble pas être quelque chose de vraiment nécessaire pour une collection indexée simple (comme l'IList est).

  • AddRange est fortement dépendant de l'implémentation de List.

    En parlant de la classe List<>. Il n'y a pas de classe non générique appelée List. La variante non générique s'appelle ArrayList. Et ArrayList est une sorte de synonyme de Tableau Dynamique en termes de structures de données. Je ne sais pas pourquoi il a été décidé de renommer ArrayList en List dans les collections génériques, mais je pense que cela augmente simplement la confusion sur ces classes en C#. Ainsi, List est en fait un tableau dynamique. Et un tableau dynamique aurait de gros problèmes de performance si vous ajoutez un grand nombre d'éléments un par un. Donc AddRange est une méthode auxiliaire et, dans un sens, nécessaire pour un tableau dynamique. Mais elle n'est pas du tout nécessaire pour une collection indexée, qui est ce que l'IList est.

En conclusion, je tiens à dire que List et IList (tout comme ArrayList et IList) sont en fait des entités qui ont une signification différente, et vous ne devez pas les considérer comme interchangeables. Mais il y a certaines mauvaises décisions concernant les noms et les relations d'interface qui ont été prises et ont conduit à une incompréhension croissante de la relation entre List et IList.

2voto

wertzui Points 2071

Depuis C#7, nous disposons de la correspondance de modèles que nous pouvons facilement utiliser pour appeler la méthode List.AddRange(), plus performante, et n'avons pas besoin d'utiliser la conversion as.

public static void AddRange(this ICollection collection, IEnumerable items)
{
    if (collection is null)
        throw new ArgumentNullException(nameof(collection));
    if (items is null)
        throw new ArgumentNullException(nameof(items));

    switch (collection)
    {
        case List list:
            list.AddRange(items);
            break;
        default:
            foreach (var item in items)
            {
                collection.Add(item);
            }
            break;
    }
}

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