Pregunta

¿Cuál es el tipo de contenedor preferido al devolver múltiples objetos del mismo tipo desde una función?

¿Está en contra de las buenas prácticas devolver una matriz simple (como MyType []), o debería envolverla en algún contenedor genérico (como ICollection < MyType >)?

¡Gracias!

¿Fue útil?

Solución

Eric Lippert tiene un buen artículo sobre esto. En caso de que no pueda molestarse en leer el artículo completo, la respuesta es: devolver la interfaz.

Otros consejos

Devuelva un IEnumerable<T> utilizando un yield return .

Devolvería un IList<T> ya que eso le da al consumidor de su función la mayor flexibilidad. De esa forma, si el consumidor de su función solo necesita enumerar la secuencia, puede hacerlo, pero si quiere usar la secuencia como una lista, también puede hacerlo.

Mi regla general es aceptar el tipo menos restrictivo como parámetro y devolver el tipo más rico que pueda. Esto es, por supuesto, un acto de equilibrio, ya que no desea encerrarse en una interfaz o implementación en particular (pero siempre trate de usar una interfaz).

Este es el enfoque menos presuntuoso que usted, el desarrollador de API, puede adoptar. No depende de usted decidir cómo un consumidor de su función utilizará lo que le envían; es por eso que devolvería un IEnumerable<T> en este caso para darles la mayor flexibilidad. Además, por esta misma razón, nunca presumiría saber qué tipo de parámetro le enviará un consumidor. Si solo necesita iterar una secuencia que se le envió como parámetro, haga que el parámetro sea List<T> en lugar de <=>.


EDITAR (monóxido): Como no parece que la pregunta vaya a cerrarse, solo quiero agregar un enlace de la otra pregunta sobre esto: ¿Por qué las matrices son perjudiciales?

¿Por qué no List<T>?

De la publicación de Eric Lippert mencionada por otros, pensé que destacaría esto:

  

Si necesito una secuencia, & # 8217; usaré   IEnumerable<T>, si necesito un mapeo   de números contiguos a datos I & # 8217; ll   use un Dictionary<K,V>, si necesito un mapeo   a través de datos arbitrarios I & # 8217; usaré un   HashSet<T>, si necesito un conjunto I & # 8217; ll   use un <=>. Simplemente no & # 8217; no necesito   matrices para cualquier cosa, así que casi nunca   usalos, usalos a ellos. No & # 8217; no resuelven un problema I   tener mejores que las otras herramientas en mi   eliminación.

Si la colección que se devuelve es de solo lectura, lo que significa que nunca desea que se modifiquen los elementos de la colección, utilice IEnumerable<T>. Esta es la representación más básica de una secuencia de solo lectura de elementos inmutables (al menos desde la perspectiva de la enumeración misma).

Si desea que sea una colección independiente que se puede cambiar, utilice ICollection<T> o IList<T>.

Por ejemplo, si desea devolver los resultados de la búsqueda de un conjunto particular de archivos, devuelva IEnumerable<FileInfo>.

Sin embargo, si desea exponer los archivos en un directorio, sin embargo, expondría IList/ICollection<FileInfo> ya que tiene sentido que posiblemente desee cambiar el contenido de la colección.

Un buen consejo que a menudo escuché citado es este:

  

Sea liberal en lo que acepta, preciso en lo que proporciona.

En términos de diseño de su API, le sugiero que devuelva una interfaz, no un tipo concreto.

Tomando su método de ejemplo, lo reescribiría de la siguiente manera:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

La clave es que su elección de implementación interna (usar una Lista) no se revela a la persona que llama, pero está devolviendo una interfaz adecuada.

Las propias pautas de Microsoft sobre desarrollo de marcos recomiendan no devolver tipos específicos, favoreciendo las interfaces. (Lo siento, no pude encontrar un enlace para esto)

Del mismo modo, sus parámetros deben ser lo más generales posible: en lugar de aceptar una matriz, acepte un IEnumerable del tipo apropiado. Esto es compatible con matrices, así como con listas y otros tipos útiles.

Tomando de nuevo tu método de ejemplo:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}
return ICollection<type>

La ventaja de los tipos de retorno genéricos es que puede cambiar la implementación subyacente sin cambiar el código que la usa. La ventaja de devolver el tipo específico es que puede usar más métodos específicos de tipo.

Siempre devuelve un tipo de interfaz que presenta la mayor cantidad de funcionalidad para la persona que llama. Entonces, en su caso, debería usarse ICollection<YourType>.

Algo interesante a tener en cuenta es que los desarrolladores de BCL realmente se equivocaron en algún lugar del marco .NET; consulte esta publicación del blog de Eric Lippert para esa historia.

¿Por qué no IList<MyType>?

Es compatible con la indexación directa, que es el sello distintivo de una matriz sin eliminar la posibilidad de devolver un List<MyType> algún día. Si desea suprimir esta función, probablemente desee devolver IEnumerable<MyType>.

Depende de lo que planeas hacer con la colección que estás devolviendo. Si solo está iterando, o si solo desea que el usuario repita, entonces estoy de acuerdo con @Daniel, devuelva IEnumerable<T>. Sin embargo, si realmente desea permitir operaciones basadas en listas, devolvería IList<T>.

Use genéricos. Es más fácil interactuar con otras clases de colecciones y el sistema de tipos es más capaz de ayudarlo con posibles errores.

El viejo estilo de devolver una matriz era una muleta antes de los genéricos.

Lo que hace que su código sea más legible, fácil de mantener y más fácil para USTED. Hubiera utilizado la matriz simple, más simple == mejor la mayor parte del tiempo. Aunque realmente tengo que ver el contexto para dar la respuesta correcta.

Hay grandes ventajas en favorecer IEnumerable sobre cualquier otra cosa, ya que esto le brinda la mayor flexibilidad de implementación y le permite utilizar operadores yield return o Linq para una implementación diferida.

Si la persona que llama quiere un List<T> en su lugar, simplemente puede llamar a ToList() lo que haya devuelto, y el rendimiento general será más o menos el mismo que si hubiera creado y devuelto un nuevo <=> de su método.

La matriz es dañina, pero ICollection<T> también es dañina.

ReadOnlyCollection<T> no puede garantizar que el objeto sea inmutable.

Mi recomendación es envolver el objeto devuelto con <=>

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top