Para responder a la parte del "por qué" de la pregunta de por qué no List<T>
, los motivos son a prueba de futuro y la simplicidad de la API.
A prueba de futuro
List<T>
no está diseñado para ser fácilmente extensible subclasificándolo; Está diseñado para ser rápido para implementaciones internas. Notará que los métodos en él no son virtuales y, por lo tanto, no pueden anularse, y no hay ganchos en sus operaciones Add
/ Insert
/ Remove
.
Esto significa que si necesita alterar el comportamiento de la colección en el futuro (por ejemplo, para rechazar objetos nulos que las personas intentan agregar, o para realizar un trabajo adicional cuando esto sucede, como actualizar su estado de clase), entonces debe cambiar el tipo de la colección que regresa a una que puede subclasificar, lo que será un cambio de interfaz de última hora (por supuesto, cambiar la semántica de cosas como no permitir nulo también puede ser un cambio de interfaz, pero cosas como actualizar su estado interno de clase no lo serían).
Así que, ya sea mediante la devolución de una clase que puede ser fácilmente subclases tales como Collection<T>
o una interfaz como IList<T>
, ICollection<T>
oIEnumerable<T>
puede cambiar su implementación interna para que sea un tipo de colección diferente para satisfacer sus necesidades, sin romper el código de los consumidores porque aún puede devolverse como el tipo que esperan
Simplicidad API
List<T>
contiene muchas operaciones útiles como BinarySearch
, Sort
etc. Sin embargo, si esta es una colección que está exponiendo, es probable que controle la semántica de la lista, y no los consumidores. Entonces, aunque su clase internamente pueda necesitar estas operaciones, es muy poco probable que los consumidores de su clase quieran (o incluso deberían) llamarlos.
Como tal, al ofrecer una clase o interfaz de colección más simple, reduce la cantidad de miembros que ven los usuarios de su API y les facilita su uso.
Yo personalmente declararía que devolvería una interfaz en lugar de una colección concreta. Si realmente quieres acceder a la lista, úsala
IList<T>
. De lo contrario, considereICollection<T>
yIEnumerable<T>
.fuente
We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs.
CA1002 parece coincidir con los comentarios de Krzysztof. No puedo imaginar por qué se recomendaría una colección concreta en lugar de una interfaz, y por qué la distinción entre entradas / salidas.ReadOnlyCollection<T>
no tendría sentido para una entrada. Del mismo modo,IList<T>
como dice una entrada, "Necesito Sort () o algún otro miembro que tenga una IList" que no tiene sentido para una salida. Pero lo que quise decir fue, ¿por qué seICollection<T>
recomendaría como entrada yCollection<T>
como salida? ¿Por qué no usarICollection<T>
como salida también como sugeriste?Collection<T>
yReadOnlyCollection<T>
ambos derivan deICollection<T>
(es decir, no hayIReadOnlyCollection<T>
). Si devuelve la interfaz, no es obvio cuál es y si se puede modificar. De cualquier forma, gracias por tu aporte. Este fue un buen control de cordura para mí.No creo que nadie haya respondido la parte del "por qué" todavía ... así que aquí va. La razón por la cual "usted" debería "usar un
Collection<T>
lugar de unList<T>
es porque si expone unList<T>
, entonces cualquiera que tenga acceso a su objeto puede modificar los elementos de la lista. MientrasCollection<T>
se supone que indica que está haciendo sus propios métodos "Agregar", "Eliminar", etc.Es probable que no tenga que preocuparse por ello, porque probablemente esté codificando la interfaz solo para usted (o tal vez para algunos colegas). Aquí hay otro ejemplo que podría tener sentido.
Si tiene una matriz pública, por ejemplo:
Se podría pensar que debido a que solo hay un descriptor de acceso "get" que nadie puede interferir con los valores, pero eso no es cierto. Cualquiera puede cambiar los valores allí dentro de la siguiente manera:
Personalmente, solo lo usaría
List<T>
en la mayoría de los casos. Pero si está diseñando una biblioteca de clases que va a entregar a desarrolladores aleatorios, y necesita confiar en el estado de los objetos ... entonces querrá hacer su propia Colección y bloquearla desde allí: )fuente
Se trata principalmente de abstraer sus propias implementaciones en lugar de exponer el objeto List para que sea manipulado directamente.
No es una buena práctica dejar que otros objetos (o personas) modifiquen el estado de sus objetos directamente. Piense en captadores / establecedores de propiedades.
Colección -> Para colección normal
ReadOnlyCollection -> Para colecciones que no deben modificarse
KeyedCollection -> Cuando desee diccionarios en su lugar.
La forma de solucionarlo depende de lo que desee que haga su clase y del propósito del método GetList (). ¿Puedes elaborar?
fuente
ReadOnlyCollection
los otros dos no lo obedece.GetList()
poder ayudarlo más correctamente.Collection<T>
ayuda a abstraer la implementación interna y evita la manipulación directa de la lista interna. ¿Cómo?Collection<T>
es simplemente un contenedor, que opera en la misma instancia pasada. Es una colección dinámica destinada a la herencia, nada más (la respuesta de Greg es más relevante aquí).En este tipo de casos, generalmente trato de exponer la menor cantidad de implementación necesaria. Si los consumidores no necesitan saber que realmente está utilizando una lista, entonces no necesita devolver una lista. Al regresar cuando Microsoft sugiere una Colección, oculta el hecho de que está utilizando una lista de los consumidores de su clase y los aísla de un cambio interno.
fuente
Algo que agregar, aunque ha pasado mucho tiempo desde que se le preguntó.
Cuando su tipo de lista se deriva de, en
List<T>
lugar deCollection<T>
, no puede implementar los métodos virtuales protegidos queCollection<T>
implementa. Lo que esto significa es que su tipo derivado no puede responder en caso de que se realicen modificaciones en la lista. Esto se debe a queList<T>
asume que usted es consciente cuando agrega o elimina elementos. Ser capaz de responder a las notificaciones es una sobrecarga y, por lo tanto,List<T>
lo no lo ofrece.En los casos en que el código externo tiene acceso a su colección, es posible que no tenga el control de cuándo se agrega o elimina un elemento. Por lo tanto,
Collection<T>
proporciona una manera de saber cuándo se modificó su lista.fuente
No veo ningún problema al devolver algo como
Si devolví una copia desconectada de los datos internos o el resultado separado de una consulta de datos, puedo regresar de manera segura
List<TItem>
sin exponer ninguno de los detalles de implementación y permitir el uso de los datos devueltos de la manera conveniente.Pero esto depende del tipo de consumidor que espero: si se trata de una cuadrícula de datos que prefiero devolver,
IEnumerable<TItem>
que de todos modos será la lista de elementos copiados en la mayoría de los casos :)fuente
Bueno, la clase Colección es realmente una clase envolvente alrededor de otras colecciones para ocultar sus detalles de implementación y otras características. Creo que esto tiene algo que ver con la propiedad de ocultar el patrón de codificación en lenguajes orientados a objetos.
Creo que no debería preocuparse por eso, pero si realmente desea complacer la herramienta de análisis de código, simplemente haga lo siguiente:
fuente
Collection<T>
no protege ni a sí mismo ni a la colección subyacente por lo que yo entiendo.Collection<T>
protegerá inmediatamente su colección subyacente.