metodos - return funcion c#
¿Debo devolver una matriz o una colección desde una función? (14)
¿Por qué no IList<MyType>
?
Admite la indexación directa, que es el sello distintivo de una matriz sin eliminar la posibilidad de devolver una List<MyType>
algún día. Si desea suprimir esta función, es probable que desee devolver IEnumerable<MyType>
.
¿Cuál es el tipo de contenedor preferido al devolver varios objetos del mismo tipo desde una función?
¿Es contra la buena práctica devolver una matriz simple (como MyType []), o debe envolverla en algún contenedor genérico (como ICollection <MyType>)?
¡Gracias!
¿Por qué no List<T>
?
Desde la publicación de Eric Lippert mencionada por otros, pensé que destacaría esto:
Si necesito una secuencia,
IEnumerable<T>
, si necesito una asignación de números contiguos a datos,IEnumerable<T>
unaList<T>
, si necesito una asignación entre datos arbitrarios, usaré unDictionary<K,V>
, si necesito un conjuntoHashSet<T>
unHashSet<T>
. Simplemente no necesito arreglos para nada, así que casi nunca los uso. No resuelven un problema que tengo mejor que las otras herramientas a mi disposición.
Depende de lo que planee hacer con la colección que va a devolver. Si solo estás iterando, o si solo quieres que el usuario itere, entonces estoy de acuerdo con @Daniel, devuelve IEnumerable<T>
. Sin embargo, si realmente desea permitir operaciones basadas en listas, devolvería IList<T>
.
Eric Lippert tiene un buen article sobre esto. En caso de que no se moleste en leer el artículo completo, la respuesta es: devuelva la interfaz.
Hay grandes ventajas en favorecer a IEnumerable sobre cualquier otra cosa, ya que esto le brinda la mayor flexibilidad de implementación y le permite usar los yield return
o los operadores Linq para una implementación lenta.
Si la persona que llama quiere una List<T>
, puede simplemente llamar a ToList()
en cualquier cosa que devolvió, y el rendimiento general será aproximadamente el mismo que si hubiera creado y devuelto una nueva List<T>
de su método.
La matriz es dañina, pero ICollection<T>
también es dañina.
ICollection<T>
no puede garantizar que el objeto sea inmutable.
Mi recomendación es envolver el objeto devuelto con ReadOnlyCollection<T>
Lo que hace que su código sea más legible, fácil de mantener y más fácil para USTED. Habría usado la matriz simple, más simple == mejor la mayor parte del tiempo. Aunque realmente tengo que ver el contexto para dar la respuesta correcta.
Si la colección que se devuelve es de solo lectura, lo que significa que nunca desea que se IEnumerable<T>
los elementos de la colección, use 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 propia enumeración).
Si desea que sea una colección autocontenida que se pueda 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 quisiera 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.
Siempre devuelva un tipo de interfaz que presente la mayor cantidad de funcionalidad a la persona que llama. Por lo tanto, en su caso, se debe utilizar ICollection<YourType>
.
Algo interesante que se debe tener en cuenta es que los desarrolladores de BCL realmente se equivocaron en algún lugar del marco .NET: consulte article para esa historia.
Un buen consejo que he oído citar a menudo es este:
Sea liberal en lo que acepta, preciso en lo que proporciona.
En cuanto al 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, para usar una Lista, no se revela a la persona que llama, pero está devolviendo una interfaz adecuada.
Las propias directrices de Microsoft sobre desarrollo de marcos recomiendan no devolver tipos específicos, lo que favorece las interfaces. (Lo siento, no pude encontrar un enlace para esto)
De manera similar, sus parámetros deben ser tan generales como sea posible; en lugar de aceptar una matriz, acepte un IEnumerable del tipo apropiado. Esto es compatible con matrices, así como listas y otros tipos útiles.
Tomando su método de ejemplo de nuevo:
public IList<object> Foo(IEnumerable<object> bar)
{
List<object> retList = new List<object>();
// Blah, blah, [snip]
return retList;
}
Usa los genéricos. Es más fácil interoperar 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.
IList<T>
un IList<T>
ya que le da al consumidor de su función la mayor flexibilidad. De esa manera, si el consumidor de su función solo necesitaba enumerar la secuencia, pueden hacerlo, pero si quieren usar la secuencia como una lista, también pueden 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 quiere bloquearse en ninguna interfaz o implementación en particular (pero siempre, 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 usará lo que le envían, es por eso que en este caso devolvería un IList<T>
para darles la mayor flexibilidad. Además, por este mismo motivo, nunca debe suponer qué tipo de parámetro le enviará un consumidor. Si solo necesita iterar una secuencia que se le envió como un parámetro, haga que el parámetro sea un IEnumerable<T>
lugar de una List<T>
.
EDITAR (monóxido): Ya que no parece que la pregunta vaya a cerrarse, solo quiero agregar un enlace de la otra pregunta sobre esto: article
Devuelve un IEnumerable<T>
utilizando un yield return
.
return ICollection<type>
La ventaja de los tipos de devolución genéricos es que puede cambiar la implementación subyacente sin cambiar el código que la utiliza. La ventaja de devolver el tipo específico, es que puede usar más métodos específicos de tipo.