2009-03-02 12 views
15

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

¿Es contra la buena práctica devolver una matriz simple (como MyType []), o debería envolverla en algún contenedor genérico (como ICollection <MyType>)?

Gracias!

+0

(respuestas combinadas de reciente duplicado) –

Respuesta

15

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

+0

devuelto +1 Habría publicado ese mismo enlace si aún no lo hubiera hecho. –

+0

¡Un gran hallazgo! Lo estoy leyendo ahora. ¡Gracias! – Pwninstein

0

Use 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.

3

Devuelva siempre un tipo de interfaz que presente la mayor cantidad de funcionalidad a la persona que llama. Por lo tanto, en su caso ICollection<YourType> debe ser utilizado.

Algo interesante a tener en cuenta es que los desarrolladores de BCL en realidad obtuvieron este error en algún lugar del framework .NET - vea this Eric Lippert blog post para esa historia.

+0

Como él dice, no se equivocan, pero no tenían los genéricos disponibles como una opción (que eran introducido en CLR 2.0). – erikkallen

+0

Sé a lo que te refieres, pero para citar el artículo: "Permíteme darte un ejemplo de dónde obtuvimos ese horrible error de una manera muy visible en el marco". :) –

6

¿Por qué no List<T>?

Desde el puesto de Eric Lippert mencionado otros, pensé voy a destacar lo siguiente:

Si necesito una secuencia usaré IEnumerable<T>, si necesito un mapeo de números contiguos a los datos I te utilizar un List<T>, si necesito un mapeo través de datos arbitrarios voy a usar un Dictionary<K,V>, si necesito un conjunto voy a uso un HashSet<T>. Simplemente no necesito las matrices para nada, así que casi nunca las uso. No resuelven un problema I tienen mejor que las otras herramientas en mi disposición .

+0

Bueno, depende de lo que tiene que hacer con el valor devuelto. IList y List no tienen el mismo conjunto de métodos disponibles (la lista tiene más métodos disponibles). Si no necesita ninguno de esos métodos, devolver IList void será la mejor solución, ya que la regla general es devolver el tipo que infiera la menor cantidad de restricciones. Sin embargo, hay una gran diferencia entre usar/argumento, variabl local) y regresar. cuando usa algo, sabe cómo se usa, cuando devuelve algo, no puede estar seguro del uso del –

0

Lo que hace que su código sea más legible, fácil de mantener y más fácil para USTED. Hubiera 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.

4
return ICollection<type> 

La ventaja para los tipos de devolución 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 puedes usar más métodos específicos del tipo.

1

¿Por qué no IList<MyType>?

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

5

Si la colección que se devuelve es de solo lectura, lo que significa que nunca desea que se cambien 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, entonces devuelva IEnumerable<FileInfo>.

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

+0

IEnumerabl es _no_ una colección de solo lectura. Es una interfaz general para una secuencia y si los elementos son inmutables o no depende de que los objetos de T sean inmutables o no. cualquier objeto de la lista es un IEnumerable pero eso ciertamente no hace que la lista sea una colección de solo lectura –

+0

@runefs: Leyó mal. No estoy hablando de la inmutabilidad de las instancias devueltas, sino más bien de la inmutabilidad de la secuencia en sí misma. – casperOne

0

Hay grandes ventajas en favorecer IEnumerable sobre cualquier otra cosa, ya que esto le da la mayor flexibilidad de implementación y le permite usar los operadores yield return o Linq para la implementación perezosa.

Si la persona que llama quiere un lugar List<T> pueden simplemente llaman ToList() en lo que regresó, y el rendimiento general serán más o menos lo mismo que si hubiera creado un nuevo y regresó List<T> de su método.

0

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

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

Mi recomendación es envolver el objeto de regresar con ReadOnlyCollection<T>

12

Devolver una IEnumerable<T> utilizando un yield return.

+0

Sugerencia interesante, nunca pensé en eso. –

+0

He estado empezando a usar esto mucho, y realmente crea un código realmente elegante con LINQ. –

+0

+1 No estaba de acuerdo hasta que agregó "usando un retorno de rendimiento". Los bloques Iterator son una herramienta muy poderosa que, si se usa correctamente, puede optimizar su código y la huella de su memoria. –

8

Devolvería un IList<T> ya que le da al consumidor de su función la mayor flexibilidad. De esta forma, si el consumidor de su función solo necesita enumerar la secuencia, puede hacerlo, pero si quiere usar la secuencia como 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, siempre trate de usar una interfaz).

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


EDITAR (monóxido): Ya que no se parece a la pregunta va a ser cerrada, sólo quiero añadir un enlace desde la otra pregunta acerca de esto: Why arrays are harmful

+0

Bien dicho. – Shog9

1

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

5

Un buen consejo que yo he oído tantas veces citado es la siguiente:

ser liberal en lo que acepta, preciso en lo que usted proporciona.

En cuanto al diseño de su API, le sugiero que devuelva una interfaz, no un tipo concreto.

Llevar a su método de ejemplo, me gustaría volver a escribir 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 implementación interna - Para utilizar una lista - no se revela a la persona que llama, pero eres devolviendo una interfaz apropiada.

Las propias directrices de Microsoft sobre el desarrollo del framework recomiendan no devolver tipos específicos, lo que favorece las interfaces. (Lo siento, no he podido 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, listas y otros tipos útiles.

Llevar a 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; 
} 
Cuestiones relacionadas