c# - ejemplo - ienumerable string
¿Tiene una ICollection<T> una orden? (9)
Siguiendo las reglas de que las API públicas nunca deben devolver una lista , estoy cegando la conversión de todo el código que devolvió las listas, para devolver ICollection<T>
lugar:
public IList<T> CommaSeparate(String value) {...}
se convierte en
public ICollection<T> CommaSeparate(String value) {...}
Y aunque una ICollection
tiene un Count
, no hay forma de obtener elementos por ese índice.
Y aunque una ICollection
expone un enumerador (permitiendo foreach
), no veo ninguna garantía de que el orden de enumeración comience en la "parte superior" de la lista, a diferencia de la "parte inferior".
Podría mitigar esto evitando el uso de ICollection
y, en su lugar, utilizar Collection
:
public Collection<T> Commaseparate(String value) {...}
Esto permite el uso de una sintaxis de Items[index]
.
Desafortunadamente, mi implementación interna construye una matriz; que puedo ser lanzado para devolver IList
o ICollection
, pero no como una Collection
.
¿Hay alguna forma de acceder a los elementos de una colección en orden ?
Esto plantea la pregunta más amplia: ¿Una colección de IC incluso tiene un pedido?
Conceptualmente, imagine que quiero analizar una cadena de línea de comandos. Es crítico que el orden de los artículos se mantenga.
Conceptualmente, requiero un contrato que indique un conjunto "ordenado" de tuplas de cadena. En el caso de un contrato de API, para indicar el orden, cuál de los siguientes es correcto:
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)
Depende de la implementación de la instancia. Una ICollection que pasa a ser una Lista tiene un orden, una ICollection que pasa a ser una Colección no.
Todas las implementaciones de ICollections IEnumerable, que devuelven los artículos uno por uno, ordenados o no.
EDITAR: En respuesta a su ejemplo adicional sobre el análisis de la línea de comandos en la pregunta, argumentaría que el tipo de retorno apropiado depende de lo que esté haciendo 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 por Grob, lo que probablemente no desee. Dado que .NET no tiene una interfaz de secuencia indexada, IEnumerable es la mejor opción para evitar que sus interlocutores hagan algo extraño, como intentar modificar la lista de parámetros que recuperan.
ICollection no tiene un orden garantizado, pero la clase que realmente lo implementa puede (o no).
Si desea devolver una colección ordenada, devuelva un IList<T>
y no se preocupe demasiado por los consejos generalmente sólidos pero genéricos de FxCop.
La 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 de Values
de un SortedDictionary
, los objetos estarán en el orden definido por el comparador del diccionario.
Si necesita el método para devolver, mediante contrato, un tipo cuyo contrato requiera un cierto pedido, debe expresarlo en la firma del método devolviendo el tipo más específico.
Independientemente del tipo de tiempo de ejecución del objeto devuelto, considere el comportamiento cuando la referencia estática es IList<T>
o ICollection<T>
: cuando llama a GetEnumerator()
(quizás implícitamente en un bucle foreach), usted llamará al mismo método y obtener el mismo objeto independientemente del tipo estático de la referencia. Por lo tanto, se comportará de la misma manera, independientemente del tipo de retorno del método CommaSeparate()
.
Pensamiento adicional:
Como alguien más señaló, la regla FXCop advierte contra el uso de List<T>
, no IList<T>
; La pregunta a la que se vinculó es la pregunta de por qué FXCop no recomienda usar IList<T>
en lugar de la 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.
La instancia de ICollection
tiene el "orden" de cualquier clase que lo implemente. Es decir, hacer referencia a una List<T>
como una ICollection
no alterará su orden en absoluto.
Del mismo modo, si accede a una colección desordenada como una colección ICollection
, tampoco impondrá una orden en la colección desordenada.
Por lo tanto, a su pregunta:
¿Una colección de IC incluso tiene una orden?
La respuesta es: depende únicamente de la clase que la implementa.
No, ICollection no implica un pedido.
Si espera que todas las versiones actuales y futuras de su método no tendrán dificultades para devolver un objeto que pueda recuperar rápida y fácilmente el artículo Nth, use el tipo IList<T>
para devolver una referencia a algo que implemente ambas IList<T>
e ICollection
no genérico. Si espera que algunas versiones actuales o futuras no puedan devolver el Noveno artículo rápida y fácilmente, pero podrían informar el número de elementos de manera instantánea, use el tipo ICollection<T>
para devolver una referencia que implemente ICollection<T>
e ICollection
no genérico. Si espera que las versiones actuales o futuras puedan tener problemas incluso al saber cuántos elementos hay, devuelva IEnumerable<T>
. La cuestión de la secuenciación es irrelevante; la capacidad de acceder a la Novena cosa implica que existe una secuencia definida, pero ICollection<T>
no dice más ni menos acerca de la secuenciación que IEnumerable<T>
.
Una ICollection<T>
es solo una interfaz; Si está ordenado o no, depende totalmente de la implementación subyacente (que se supone que es opaca).
Si desea poder acceder a él por medio de un índice, debería devolver las cosas como un IList<T>
, que es IEnumerable<T>
e 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 un tiempo O (N / 2) en el promedio.
Mi inclinación sería evitar por completo las interfaces de ''colección'' y, en su lugar, utilizar un tipo personalizado que represente la colección en términos del dominio del problema y que exponga las operaciones lógicas apropiadas adecuadas para ese tipo.
ICollection<T>
puede tener un pedido, pero el orden real depende de la clase que lo implemente. No tiene accesorios para un artículo en el índice dado. IList<T>
especializa esta interfaz para proporcionar acceso por índice.
ICollection
es solo una interfaz, no hay implementación ni especificación explícita sobre el pedido. Eso significa que si devuelve algo que se enumera de una manera ordenada, lo que sea que esté consumiendo su ICollection
lo hará de manera ordenada.
La orden solo está implícita por el objeto subyacente, de implementación , No hay ninguna especificación en ICollection
que diga que se debe ordenar o no. Enumerar un resultado varias veces invocará el enumerador del objeto subyacente, que es el único lugar donde se establecerán esas reglas. Un objeto no cambia la forma en que se enumera simplemente porque hereda esta interfaz. Si la interfaz especificara que es un resultado ordenado, entonces podría confiar en el resultado ordenado del objeto implementado.