¿Hay alguna razón para exponer una colección interna como ReadOnlyCollection en lugar de IEnumerable si el código de llamada solo itera sobre la colección?
class Bar
{
private ICollection<Foo> foos;
// Which one is to be preferred?
public IEnumerable<Foo> Foos { ... }
public ReadOnlyCollection<Foo> Foos { ... }
}
// Calling code:
foreach (var f in bar.Foos)
DoSomething(f);
A mi entender, IEnumerable es un subconjunto de la interfaz de ReadOnlyCollection y no permite al usuario modificar la colección. Entonces, si la interfaz IEnumberable es suficiente, entonces esa es la que hay que usar. ¿Es esa una forma adecuada de razonar al respecto o me estoy perdiendo algo?
Gracias / Erik
c#
.net
collections
ienumerable
readonly-collection
Erik Öjebo
fuente
fuente
ReadOnlyCollection
si eres paranoico, pero ahora no estás atado a una implementación específica.Respuestas:
Solución más moderna
A menos que necesite que la colección interna sea mutable, puede usar el
System.Collections.Immutable
paquete, cambiar su tipo de campo para que sea una colección inmutable y luego exponerlo directamente, suponiendo queFoo
sea inmutable, por supuesto.Respuesta actualizada para abordar la pregunta más directamente
Depende de cuánto confíes en el código de llamada. Si tiene el control total sobre todo lo que alguna vez llamará a este miembro y garantiza que ningún código usará:
entonces seguro, no se hará daño si solo devuelve la colección directamente. Sin embargo, generalmente trato de ser un poco más paranoico que eso.
Del mismo modo, como dices: si solo necesitas
IEnumerable<T>
, ¿por qué atarte a algo más fuerte?Respuesta original
Si está utilizando .NET 3.5, puede evitar hacer una copia y evitar la conversión simple mediante una simple llamada para Omitir:
(Hay muchas otras opciones para ajustar trivialmente; lo bueno de
Skip
seleccionar / Dónde es que no hay delegado para ejecutar sin sentido para cada iteración).Si no está utilizando .NET 3.5, puede escribir un contenedor muy simple para hacer lo mismo:
fuente
ReadOnlyCollection
aICollection
y luego ejecutar conAdd
éxito. Que yo sepa, eso no debería ser posible. Elevil.Add(...)
debería arrojar un error. dotnetfiddle.net/GII2jWReadOnlyCollection
- lanzo unoIEnumerable<T>
que en realidad no es de solo lectura ... es en lugar de exponer unReadOnlyCollection
ReadOnlyCollection
lugar de unIEnumerable
, para protegerse contra el lanzamiento del mal.Si solo necesita recorrer la colección:
entonces devolver IEnumerable es suficiente.
Si necesita acceso aleatorio a los elementos:
luego envuélvala en ReadOnlyCollection .
fuente
System.Collections.Immutable
como recomienda Jon Skeet es perfectamente válido cuando expones algo que nunca va a cambiar después de obtener una referencia. Por otro lado, si está exponiendo una vista de solo lectura de una colección mutable, entonces este consejo sigue siendo válido, aunque probablemente lo expondría comoIReadOnlyCollection
(que no existía cuando escribí esto).bar.Foos[17]
conIReadOnlyCollection
. La única diferencia es laCount
propiedad adicional .public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
bar.Foos[17]
, debe exponerlo comoReadOnlyCollection<Foo>
. Si desea conocer el tamaño e iterar a través de él, exponerlo comoIReadOnlyCollection<Foo>
. Si no necesita saber el tamaño, úseloIEnumerable<Foo>
. Hay otras soluciones y otros detalles, pero está más allá del alcance de la discusión de esta respuesta en particular.Si hace esto, no hay nada que impida que las personas que llaman vuelvan el IEnumerable a ICollection y luego lo modifiquen. ReadOnlyCollection elimina esta posibilidad, aunque todavía es posible acceder a la colección de escritura subyacente a través de la reflexión. Si la colección es pequeña, una forma segura y fácil de solucionar este problema es devolver una copia.
fuente
Evito usar ReadOnlyCollection tanto como sea posible, en realidad es considerablemente más lento que simplemente usar una Lista normal. Ver este ejemplo:
fuente
A veces es posible que desee utilizar una interfaz, tal vez porque quiere burlarse de la colección durante las pruebas unitarias. Consulte mi entrada de blog para agregar su propia interfaz a ReadonlyCollection utilizando un adaptador.
fuente