Interfaz o clase de retorno

9

Supongamos que tengo un método

public List<User> GetBatchOfUsers(IEnumerable<int> userIDs)
{
    List<User> users = new List<User>();

    // some database stuff

    return users;
}

He leído que sería mejor devolver una interfaz (ya sea IListo IEnumerable) en lugar de devolver a List. Algunos de los argumentos que escuché al respecto es que oculta datos y le da al desarrollador de API la flexibilidad de cambiar la representación interna de los datos en una fecha posterior.

Mi preocupación acerca de solo devolver un IEnumerablees que pierdes funcionalidad, como el acceso aleatorio y la Countpropiedad.

Sé que aceptar un IEnumerableparámetro tiene sentido, ya que le da al consumidor la mejor flexibilidad para enviar datos a mi método, el conjunto minimalista de requisitos para que el método funcione.

¿Cuál es la mejor práctica para el tipo de devolución?

Mateo
fuente
55
Mucho más importante: tome una interfaz como tipo de parámetro.
Michael Borgwardt

Respuestas:

10

En términos generales, puede comenzar con las interfaces y solo moverse para poner el tipo concreto como el tipo de retorno si descubre que usa los métodos adicionales con más frecuencia de lo esperado.

Bueno, si devuelve una interfaz, conservará más flexibilidad. Puede cambiar la implementación más tarde para devolver un tipo concreto diferente. Por otro lado, obviamente le da menos información a la persona que llama, por lo que es posible que no pueda realizar ciertas operaciones. (Por ejemplo: si regresa List<T>, la persona que llama puede usar ConvertAll, etc., lo cual no puede hacer si solo declara que regresa IList<T>). En algunas situaciones, vale la pena especificar el tipo concreto.

Con respecto al método Count u Sort, no hay interfaces de recopilación estándar para eso. Sin embargo, podría escribir un método de extensión para ordenar o contar cualquier IList.

Yusubov
fuente
¿Supongo que esto no es realmente una regla difícil entonces?
Mateo
Sí, realmente depende del uso.
Yusubov
1

Si necesita que su colección tenga una Countque pueda usar ICollection<T>, que es lo suficientemente general.

dpiatkowski
fuente
-1. Conde ya se discutió y esta respuesta no añade nada nuevo
SUPERM
@Konrad Rudolph, esta no es una respuesta, es un comentario.
SuperM
@superM Creo que es lo suficientemente valioso como para merecer su propia respuesta, ya que aborda explícitamente la razón de OP para decidir contra interfaces en primer lugar.
Konrad Rudolph el
1

Devuelve lo que es prudente para el método que está definiendo. ¿Lo que está haciendo es devolver una serie de elementos (el foco está en los elementos), o está devolviendo una colección de elementos (el foco está en la colección como un todo)? ¿Vale la pena permitir variaciones en la implementación de la colección? Si nunca tiene sentido usar un generador o HashSetsimplemente usar el List.

Telastyn
fuente
1

Específico para el método de ejemplo: tiene razón en que regresar IEnmuerable<T>significaría que perdería la funcionalidad County la indexación (aunque podría usar métodos LINQ Count()y ElementAt(), que se implementan de manera eficiente si el tipo en el que se usan realmente se implementa IList<T>).

Si regresa IList<T>, perdería alguna funcionalidad, pero la ganancia en general probablemente valga la pena.

Pero aún mejor sería algo intermedio IEnumerable<T>y IList<T>, porque lo más probable es que no tenga sentido que el consumidor mute la colección devuelta, pero sí tiene sentido que use Counto indexe.

En .Net 4.5, no es tal interfaz: IReadOnlyList<T>.

svick
fuente
IReadOnlyListsuena bien cuando puedo obtener VS2013, gracias!
Mateo