Devolver ‘IList’ frente a ‘ICollection’ frente a ‘Collection’

Estoy confundido sobre qué tipo de recostackción debo devolver de mis métodos y propiedades públicos de API.

Las colecciones que tengo en mente son IList , ICollection y Collection .

¿Siempre se prefiere uno de estos tipos a los demás o depende de la situación específica?

En general, debe devolver un tipo que sea lo más general posible, es decir, que sepa lo suficiente de los datos devueltos que el consumidor necesita usar. De esta forma, tendrá una mayor libertad para cambiar la implementación de la API, sin romper el código que la está usando.

Considere también la IEnumerable como tipo de retorno. Si el resultado solo se va a repetir, el consumidor no necesita más que eso.

ICollection es una interfaz que expone la semántica de la colección, como Add() , Remove() y Count .

Collection es una implementación concreta de la ICollection .

IList es esencialmente una ICollection con acceso aleatorio basado en órdenes.

En este caso, debe decidir si sus resultados requieren semántica de lista, como indización basada en órdenes (luego use IList ) o si solo necesita devolver una “bolsa” de resultados sin ordenar (luego use ICollection ).

La principal diferencia entre IList e ICollection es que IList permite acceder a los elementos a través de un índice. IList describe tipos parecidos a una matriz. Solo se puede acceder a los elementos en un ICollection mediante enumeración. Ambos permiten la inserción y eliminación de elementos.

Si solo necesita enumerar una colección, entonces IEnumerable es preferible. Tiene dos ventajas sobre los demás:

  1. No permite cambios en la colección (pero no en los objetos referenciados, si son de tipo de referencia).

  2. Permite la mayor variedad posible de fonts, incluidas las enumeraciones que se generan algorítmicamente y no son colecciones en absoluto.

Collection es una clase base que es principalmente útil para los implementadores de colecciones. Si lo expone en interfaces (API), se excluirán muchas colecciones útiles que no se derivan de él.


Una desventaja de IList es que las matrices lo implementan pero no le permiten agregar o eliminar elementos (es decir, no puede cambiar la longitud de la matriz). Se lanzará una excepción si llama a IList.Add(item) en una matriz. La situación está algo desactivada ya que IList tiene una propiedad booleana IsReadOnly que puede verificar antes de intentar hacerlo. Pero a mis ojos, esto sigue siendo un defecto de diseño en la biblioteca . Por lo tanto, uso List directamente, cuando se requiere la posibilidad de agregar o quitar elementos.

IList es la interfaz base para todas las listas genéricas. Como se trata de una colección ordenada, la implementación puede decidir sobre el pedido, que va desde orden ordenada a orden de inserción. Además, Ilist tiene una propiedad Item que permite que los métodos lean y editen las entradas en la lista según su índice. Esto hace posible insertar, eliminar un valor en / de la lista en un índice de posición.

También desde IList : ICollection , todos los métodos de ICollection también están disponibles aquí para su implementación.

ICollection es la interfaz base para todas las colecciones genéricas. Define el tamaño, los enumeradores y los métodos de sincronización. Puede agregar o eliminar un elemento en una colección, pero no puede elegir en qué posición ocurre debido a la ausencia de propiedad del índice.

Collection proporciona una implementación para IList , IList e IReadOnlyList .

Si usa un tipo de interfaz más estrecha como ICollection lugar de IList , protegerá su código contra cambios bruscos. Si utiliza un tipo de interfaz más amplio como IList , corre más peligro de romper los cambios de código.

Citando de una fuente ,

ICollection , ICollection : desea modificar la colección o le interesa su tamaño. IList , IList : desea modificar la colección y le interesa el orden y / o el posicionamiento de los elementos en la colección.

Devolver un tipo de interfaz es más general, por lo que (sin más información sobre su caso de uso específico) me inclinaría por eso. Si desea exponer el soporte de indexación, elija IList , de lo contrario ICollection será suficiente. Finalmente, si desea indicar que los tipos devueltos son de solo lectura, elija IEnumerable .

Y, en caso de que no lo hayas leído antes, Brad Abrams y Krzysztof Cwalina escribieron un excelente libro titulado “Pautas de diseño del marco: convenciones, modismos y patrones para bibliotecas .NET reutilizables” (aquí puedes descargar un resumen).

Hay algunos temas que provienen de esta pregunta:

  • interfaces frente a clases
  • ¿Qué clase específica, de varias clases similares, colección, lista, matriz?
  • Colecciones de clases comunes frente a subitem (“generics”)

Es posible que desee resaltar que es una API orientada a objetos

interfaces frente a clases

Si no tienes mucha experiencia con interfaces, te recomiendo que uses las clases. Veo muchas veces que los desarrolladores saltan a las interfaces, incluso si no es necesario.

Y, terminar haciendo un diseño de interfaz deficiente, en lugar de un buen diseño de clase, que, dicho sea de paso, puede eventualmente migrarse a un buen diseño de interfaz …

Verá muchas interfaces en API, pero no se apresure a hacerlo, si no lo necesita.

Eventualmente aprenderá a aplicar interfaces a su código.

¿Qué clase específica, de varias clases similares, colección, lista, matriz?

Hay varias clases en c # (dotnet) que se pueden intercambiar. Como ya se mencionó, si necesita algo de una clase más específica, como “CanBeSortedClass”, explíquelo en su API.

¿Su usuario API realmente necesita saber, que su clase puede ser ordenada o aplicar algún formato a los elementos? Luego use “CanBeSortedClass” o “ElementsCanBePaintedClass”, de lo contrario use “GenericBrandClass”.

De lo contrario, use una clase más general.

Clases de colecciones comunes frente a colecciones de subitem (“generics”)

Encontrará que hay clases que contienen otros elementos, y puede especificar que todos los elementos deben ser de un tipo específico.

Las Colecciones genéricas son aquellas clases en las que puede usar la misma colección, para varias aplicaciones de código, sin tener que crear una nueva colección, para cada tipo de subelemento nuevo, como este: Colección .

¿Su usuario de API va a necesitar un tipo muy específico, el mismo para todos los elementos?

Use algo como List .

¿Tu usuario de API va a necesitar varios tipos relacionados?

Exponga List para su API y use List List , List internamente, donde Orange , Banana y Strawberry son descendientes de Fruit .

¿Su usuario de API va a necesitar una colección de tipos generics?

Use List , donde todos los elementos son object (s).

Aclamaciones.