Consulte la definición de la clase System.Array
public abstract class Array : IList, ...
Teóricamente, debería poder escribir este bit y ser feliz
int[] list = new int[] {};
IList iList = (IList)list;
También debería poder llamar a cualquier método desde iList
ilist.Add(1); //exception here
Mi pregunta no es por qué obtengo una excepción, sino por qué Array implementa IList .
c#
arrays
ilist
liskov-substitution-principle
oleksii
fuente
fuente
Respuestas:
Debido a que una matriz permite un acceso rápido por índice, y
IList
/IList<T>
son las únicas interfaces de colección que lo admiten. Entonces, tal vez su verdadera pregunta es "¿Por qué no hay una interfaz para colecciones constantes con indexadores?" Y a eso no tengo respuesta.Tampoco hay interfaces de solo lectura para colecciones. Y me faltan esos más que una interfaz de tamaño constante con indexadores.
En mi opinión, debería haber varias interfaces de colección más (genéricas) dependiendo de las características de una colección. Y los nombres también deberían haber sido diferentes,
List
porque algo con un indexador es realmente estúpido en mi opinión.IEnumerable<T>
ICollection<T>
IList<T>
Creo que las interfaces de colección actuales son de mal diseño. Pero dado que tienen propiedades que le indican qué métodos son válidos (y esto es parte del contrato de estos métodos), no se rompe el principio de sustitución.
fuente
add
y, por lo tanto, no puede sustituirse por algo que sí lo hace cuando se requiere esa habilidad.IsFixedSize
yIsReadOnly
, definitivamente viola el principio Tell, Don't Ask y el Principio de menor sorpresa . ¿Por qué implementar una interfaz cuando solo vas a lanzar excepciones para 4 de los 9 métodos?La sección de comentarios de la documentación de
IList
diceObviamente, las matrices caen en la categoría de tamaño fijo, por lo que por la definición de la interfaz tiene sentido.
fuente
Array
esto, implementa elAdd
método explícitamente, lo que reduce el riesgo de llamarlo por accidente.IList
eso, no se permite la modificación ni la adición / eliminación. Entonces la documentación ya no es correcta. : PPorque no todos los
IList
s son mutables (verIList.IsFixedSize
yIList.IsReadOnly
), y las matrices ciertamente se comportan como listas de tamaño fijo.Si su pregunta es realmente "por qué implementa una interfaz no genérica ", entonces la respuesta es que existían antes de que aparecieran los genéricos.
fuente
IList
sí misma le dice que puede no ser mutable. Si de hecho se garantizara que fuera mutable y la matriz le dijera lo contrario, entonces rompería la regla.IList<T>
y no lo rompe en caso de no genéricoIList
: enterprisecraftsmanship.com/2014/11/22/…Es un legado que tenemos de los tiempos en que no estaba claro cómo lidiar con las colecciones de solo lectura y si Array es de solo lectura. Hay indicadores IsFixedSize e IsReadOnly en la interfaz IList. El indicador IsReadOnly significa que la colección no se puede cambiar en absoluto y IsFixedSize significa que la colección permite la modificación, pero no la adición o eliminación de elementos.
En el momento de .Net 4.5, estaba claro que se requieren algunas interfaces "intermedias" para trabajar con colecciones de sólo lectura, por lo que
IReadOnlyCollection<T>
yIReadOnlyList<T>
se introdujeron.Aquí hay una gran publicación de blog que describe los detalles: Colecciones de solo lectura en .NET
fuente
La definición de interfaz IList es "Representa una colección no genérica de objetos a los que se puede acceder individualmente por índice". La matriz satisface completamente esta definición, por lo que debe implementar la interfaz. La excepción al llamar al método Add () es "System.NotSupportedException: la colección era de un tamaño fijo" y se produjo porque la matriz no puede aumentar su capacidad dinámicamente. Su capacidad se define durante la creación del objeto de matriz.
fuente
Tener un arreglo implementado IList (y transitivamente, ICollection) simplificó el motor Linq2Objects, ya que convertir el IEnumerable a IList / ICollection también funcionaría para los arreglos.
Por ejemplo, un Count () termina llamando a Array.Length bajo el capó, ya que se convierte en ICollection y la implementación de la matriz devuelve Longitud.
Sin esto, el motor Linq2Objects no tendría un tratamiento especial para las matrices y funcionaría horriblemente, o tendrían que duplicar el código agregando un tratamiento de casos especiales para las matrices (como lo hacen para IList). Deben haber optado por hacer que la matriz implemente IList en su lugar.
Esa es mi opinión sobre "Por qué".
fuente
También detalles de implementación LINQ Últimas comprobaciones de IList, si no implementa la lista necesitarían 2 comprobaciones que ralenticen todas las últimas llamadas o que el último en una matriz tome O (N)
fuente