Voir la définition de la classe System.Array
public abstract class Array : IList, ...
Théoriquement, je devrais être capable d'écrire ce morceau et être heureux
int[] list = new int[] {};
IList iList = (IList)list;
Je devrais aussi pouvoir appeler n'importe quelle méthode de l'iList
ilist.Add(1); //exception here
Ma question n'est pas pourquoi j'obtiens une exception, mais plutôt pourquoi Array implémente IList ?
Réponses:
Parce qu'un tableau permet un accès rapide par index, et
IList
/IList<T>
est sont les seules interfaces de collecte qui prennent en charge cela. Alors peut-être que votre vraie question est "Pourquoi n'y a-t-il pas d'interface pour les collections constantes avec indexeurs?" Et à cela je n'ai pas de réponse.Il n'y a pas non plus d'interfaces en lecture seule pour les collections. Et il me manque encore plus qu'une interface de taille constante avec indexeurs.
OMI, il devrait y avoir plusieurs interfaces de collecte (génériques) supplémentaires en fonction des caractéristiques d'une collection. Et les noms auraient dû être différents aussi,
List
car quelque chose avec un indexeur est vraiment stupide IMO.IEnumerable<T>
ICollection<T>
IList<T>
Je pense que les interfaces de collection actuelles sont de mauvaise conception. Mais comme ils ont des propriétés vous indiquant quelles méthodes sont valides (et cela fait partie du contrat de ces méthodes), cela ne rompt pas le principe de substitution.
la source
add
et ne peut donc pas être remplacé par quelque chose qui le fait lorsque cette capacité est requise.IsFixedSize
etIsReadOnly
, cela viole définitivement le principe Tell, Don't Ask et le principe de la moindre surprise . Pourquoi implémenter une interface alors que vous allez simplement lancer des exceptions pour 4 des 9 méthodes?La section des remarques de la documentation pour
IList
ditDe toute évidence, les tableaux tombent dans la catégorie de taille fixe, donc par la définition de l'interface, cela a du sens.
la source
Array
il met en œuvre laAdd
méthode explicitement, ce qui réduit le risque de l'appeler par accident.IList
cela interdit à la fois la modification et l' ajout / la suppression. Ensuite, les documentations ne sont plus correctes. : PParce que tous les
IList
s ne sont pas mutables (voirIList.IsFixedSize
etIList.IsReadOnly
), et que les tableaux se comportent certainement comme des listes de taille fixe.Si votre question est vraiment "pourquoi implémente-t-elle une interface non générique ", alors la réponse est que ces derniers existaient avant l'arrivée des génériques.
la source
IList
elle-même vous dit qu'elle n'est peut-être pas modifiable. S'il était en fait garanti d'être mutable et que le tableau vous disait le contraire, alors il enfreindrait la règle.IList<T>
et ne le casse pas en cas de non génériqueIList
: enterprisecraftsmanship.com/2014/11/22/...C'est un héritage que nous avons de l'époque où il n'était pas clair comment gérer les collections en lecture seule et si Array était en lecture seule ou non. Il existe des indicateurs IsFixedSize et IsReadOnly dans l'interface IList. L'indicateur IsReadOnly signifie que la collection ne peut pas du tout être modifiée et IsFixedSize signifie que la collection autorise la modification, mais pas l'ajout ou la suppression d'éléments.
Au moment de .Net 4.5, il était clair que certaines interfaces «intermédiaires» sont nécessaires pour fonctionner avec des collections en lecture seule,
IReadOnlyCollection<T>
etIReadOnlyList<T>
ont donc été introduites.Voici un excellent article de blog décrivant les détails: Collections en lecture seule dans .NET
la source
La définition de l'interface IList est «Représente une collection non générique d'objets auxquels on peut accéder individuellement par index». Array satisfait complètement cette définition, il doit donc implémenter l'interface. L'exception lors de l'appel de la méthode Add () est "System.NotSupportedException: la collection était de taille fixe" et s'est produite car le tableau ne peut pas augmenter sa capacité de manière dynamique. Sa capacité est définie lors de la création de l'objet tableau.
la source
Le fait d'avoir un tableau implémentant IList (et de manière transitoire ICollection) a simplifié le moteur Linq2Objects, car le transtypage de IEnumerable en IList / ICollection fonctionnerait également pour les tableaux.
Par exemple, un Count () finit par appeler Array.Length sous le capot, car il est converti en ICollection et l'implémentation du tableau renvoie Length.
Sans cela, le moteur Linq2Objects n'aurait pas de traitement spécial pour les tableaux et fonctionnerait horriblement, ou ils auraient besoin de doubler le code en ajoutant un traitement de cas spécial pour les tableaux (comme ils le font pour IList). Ils doivent avoir choisi de faire en sorte que le tableau implémente IList à la place.
C'est mon point de vue sur "Pourquoi".
la source
De plus, l'implémentation détaille LINQ Last checks pour IList, si elle n'implémentait pas la liste, ils auraient besoin soit de 2 vérifications pour ralentir tous les derniers appels, soit d'avoir Last on an Array prenant O (N)
la source