2012-01-05 15 views
18

Siguiendo las reglas que a public APIs should never return a list, estoy cegadoras convertir todo el código que regresó listas, para volver ICollection<T> lugar:¿Hay un pedido de ICollection <T>?

public IList<T> CommaSeparate(String value) {...} 

convierte

public ICollection<T> CommaSeparate(String value) {...} 

Y aunque un ICollection tiene un Count, no hay forma de obtener elementos por ese índice.

Y aunque un ICollection expone un enumerador (que permite foreach), no veo ninguna garantía de que el orden de enumeración comience en la "parte superior" de la lista, en lugar de "abajo".

i podría mitigar este evitando el uso de ICollection, y en lugar de utilizar Collection:

public Collection<T> Commaseparate(String value) {...} 

Esto permite el uso de una sintaxis Items[index].

Desafortunadamente, mi implementación interna construye una matriz; cuál yo puede ser lanzado para volver IList o ICollection, pero no como Collection.

¿Hay alguna manera de acceder a los elementos de una colección en el pedido?

Esto plantea la pregunta más amplia: ¿Un ICollection aun tienen un pedido?


Conceptualmente, imaginar Quiero analizar una cadena de línea de comandos. Es crítico que se mantenga el orden de los artículos.

Conceptualmente, requiero un contrato que indique un conjunto "ordenado" de tuplas de cadenas. En el caso de un contrato de API, para indicar el orden, cuál de las siguientes es correcta:

IEnumerable<String> Grob(string s) 

ICollection<String> Grob(string s) 

IList<String> Grob(string s) 

Collection<String> Grob(string s) 

List<String> Grob(string s) 
+3

Como comentario aparte, creo que leyó mal el artículo original que cita como base para su refactorización. Dice que no pase instancias de 'List ' (la clase), no 'IList ' (la interfaz). Es perfectamente legítimo en mi humilde opinión pasar 'IList 'si la interfaz requiere acceso indexado. –

+3

¿Qué pasa con IOrderedEnumerable, que devuelve LINQ OrderBy? – Euphoric

Respuesta

9

La interfaz ICollection<T> no especifica nada acerca de un pedido. Los objetos estarán en el orden especificado por el objeto devuelto. Por ejemplo, si devuelve la colección Values de SortedDictionary, los objetos estarán en el orden definido por el comparador del diccionario.

Si necesita el método para devolver, por contrato, un tipo cuyo contrato requiere un cierto orden, debe expresarlo en la firma del método devolviendo el tipo más específico.

Independientemente del tipo de ejecución del objeto devuelto, tenga en cuenta el comportamiento cuando la referencia estática es IList<T> o ICollection<T>: Cuando se llama a GetEnumerator() (quizás implícitamente en un bucle foreach), vas a llamar al mismo método y obtenga el mismo objeto independientemente del tipo de referencia estático. Por lo tanto, se comportará de la misma manera independientemente del tipo de devolución del método CommaSeparate().

pensamiento adicional:

Como lo indicó otra persona, la regla FXCop advierte contra el uso List<T>, no IList<T>; la pregunta a la que se vinculó es preguntar por qué FXCop no recomienda usar IList<T> en lugar de List<T>, que es otra cuestión. Si me imagino que está analizando una cadena de línea de comandos donde el orden es importante, me quedaría con IList<T> si fuera usted.

+0

no estoy * en realidad * devolviendo una matriz. i * suceder * para estar usando una matriz en mi implementación; pero ese es un detalle de implementación que me gustaría esconder, y se me permitirá cambiar en el futuro. –

+0

@IanBoyd entendido. Los comentarios sobre el conjunto en el último párrafo se aplicarán sin importar qué tipo se devuelva del método. Editaré para aclarar – phoog

+0

Excelente, 'IList' es entonces! –

4

La instancia ICollection tiene el "orden" de cualquier clase que lo implemente. Es decir, hacer referencia a List<T> como ICollection no alterará en absoluto su orden.

Del mismo modo, si accede a una colección desordenada como ICollection, tampoco impondrá un pedido en la colección desordenada.

Así que, a su pregunta:

hace un ICollection incluso tienen un pedido?

La respuesta es: depende únicamente de la clase que la implementa.

8

ICollection no tiene un orden garantizado, pero la clase que realmente lo implementa puede (o no).

Si desea devolver una colección ordenada, devuelva IList<T> y no se obsesione demasiado con los consejos generalmente correctos, pero muy genéricos de FxCop.

1

Depende de la implementación de la instancia. Una colección IC que es una lista tiene una orden, una colección IC que no es una colección.

Todos los ICollections implementan IEnumerable, que devuelve los elementos de uno en uno, ordenados o no.

EDITAR: En respuesta a su ejemplo adicional sobre el análisis de línea de comando en la pregunta, yo diría que el tipo de devolución apropiado depende de lo que haga con esos argumentos después, pero IEnumerable es probablemente el correcto.

Mi razonamiento es que IList, ICollection y sus implementaciones concretas permiten la modificación de la lista devuelta desde Grob, que probablemente no desee. Como .NET no tiene una interfaz de secuencia indexada, IEnumerable es la mejor opción para evitar que las personas que llaman hagan algo extraño como tratar de modificar la lista de parámetros que obtienen.

4

No, ICollection no implica un pedido.

4

ICollection es solo una interfaz — no hay implementación o especificación explícita sobre el pedido. Esto significa que si devuelve algo que se enumera de manera ordenada, lo que esté consumiendo su ICollection lo hará de manera ordenada.

El pedido solo está implícito en el objeto de implementación subyacente,, objeto. No hay ninguna especificación en ICollection que diga que debe pedirse o no. La enumeración de un resultado varias veces invocará al enumerador del objeto subyacente, que es el único lugar donde se establecerían esas reglas. Un objeto no cambia la forma en que se enumera solo porque hereda esta interfaz.Si la interfaz especificara que es un resultado ordenado, entonces podría confiar de forma segura en el resultado ordenado del objeto de implementación.

+0

'ICollection' es solo una interfaz, pero también es una declaración de reglas de comportamiento. –

+0

Absolutamente, pero no hay nada en la interfaz que diga que debe ordenarse o no. –

3

Un ICollection<T> es solo una interfaz; si está ordenado o no depende por completo de la implementación subyacente (que se supone que es opaca).

Si desea poder acceder a él por índice, querrá devolver las cosas como IList<T>, que es IEnumerable<T> y ICollection<T>. Sin embargo, se debe tener en cuenta que, dependiendo de la implementación subyacente, que obtener un elemento arbitrario en la colección podría requerir O (N/2) tiempo en promedio.

Mi inclinación sería evitar por completo las interfaces de 'colección' y usar un tipo personalizado que represente la colección en términos del dominio de problema y exponer las operaciones lógicas apropiadas adecuadas para ese tipo.

3

ICollection<T> puede tener un pedido, pero el orden real depende de la clase que lo implemente. No tiene acceso para un artículo en un índice dado. IList<T> se especializa esta interfaz para proporcionar acceso por índice.

+0

Si itero un 'ICollection' dos veces ¿obtendré elementos en el mismo orer en ambas ocasiones? –

+2

Depende de la clase que lo implemente. No está garantizado – Krizz

0

Si espera que todas las versiones presentes y futuras de su método no tengan dificultades para devolver un objeto que podrá recuperar rápida y fácilmente la enésima posición, utilice el tipo IList<T> para devolver una referencia a algo que implemente IList<T> y no genérico ICollection. Si espera que algunas versiones presentes o futuras no puedan devolver rápida y fácilmente la enésima posición, pero podría informar instantáneamente el número de elementos, use el tipo ICollection<T> para devolver una referencia que implemente ICollection<T> y no genérico . Si espera que las versiones presentes o futuras puedan tener problemas incluso sabiendo cuántos elementos hay, devuelva IEnumerable<T>. La cuestión de la secuencia es irrelevante; la capacidad de acceder a la enésima cosa implica que existe una secuencia definida, pero ICollection<T> dice ni más ni menos acerca de la secuencia que IEnumerable<T>.

Cuestiones relacionadas