Pregunta

Hay un problema con el uso de IEnumerable<T> como un tipo de retorno?FxCop queja sobre la devolución de List<T> (se aconseja volver Collection<T> en su lugar).

Bueno, yo siempre he sido guiado por una regla de "aceptar el que menos puede, pero el regreso al máximo".

Desde este punto de vista, volviendo IEnumerable<T> es una mala cosa, pero ¿qué debo hacer si quiero usar "lenta recuperación"?También, la yield palabra clave es una sorpresa.

¿Fue útil?

Solución

Esto es realmente una pregunta en dos partes.

1) ¿Hay algo malo intrínsecamente con la devolución de un IEnumerable

No hay nada en absoluto. De hecho, si usted está usando C # iteradores este es el comportamiento esperado. Convirtiéndolo en un List u otra clase de colección de forma preventiva no es una buena idea. Si lo hace, es hacer una suposición sobre el patrón de uso por la persona que llama. Me parece que no es una buena idea asumir nada acerca de la persona que llama. Pueden tener buenas razones por las que quieren un IEnumerable . Tal vez quieren convertirla en una jerarquía de la colección completamente diferente (en cuyo caso se desperdicia una conversión a la lista).

2) ¿Hay circunstancias en las que puede ser preferible a un resultado distinto del IEnumerable ?

Sí. Si bien no es una gran idea asumir mucho acerca de las personas que llaman, es perfectamente válido para tomar decisiones sobre la base de su propio comportamiento. Imagine un escenario en el que había un objeto multi-hilo que fue haciendo cola peticiones en un objeto que constantemente se está actualizando. En este caso el retorno de una prima IEnumerable es irresponsable. Tan pronto como se modifica la colección del enumerables se invalida y causará un execption que se produzca. En su lugar se puede tomar una instantánea de la estructura y devolver ese valor. Decir en una forma List . En este caso me acaba de devolver el objeto como la estructura directa (o interfaz).

Este es ciertamente el caso más raro sin embargo.

Otros consejos

No, IEnumerable<T> es una cosa bien para volver aquí, ya que todo lo que es prometedor es "una secuencia de valores (a máquina)". Ideal para LINQ, etc, y perfectamente utilizable.

La persona que llama puede poner fácilmente estos datos en una lista (o lo que sea) -. Especialmente con LINQ (ToList, ToArray, etc)

Este enfoque le permite poner en cola perezosamente valores, en lugar de tener que amortiguar todos los datos. Definitivamente una regalos. Escribí arriba otro truco útil IEnumerable<T> el otro día , también.

Sobre el principio:. "Aceptar lo menos que pueda, pero devolver el máximo"

La clave para manejar la complejidad de un programa grande es una técnica llamada ocultación de la información . Si el método funciona mediante la construcción de un List<T>, no es a menudo necesaria para revelar este hecho mediante la devolución de ese tipo. Si lo hace, entonces las personas que llaman pueden modificar la lista de que vuelvan. Esto elimina su capacidad para hacer el almacenamiento en caché, o iteración perezoso con yield return.

Así que es mejor un principio para una función a seguir es:. "Revelar lo menos posible sobre la forma de trabajar"

IEnumerable está bien para mí, pero tiene algunos inconvenientes. El cliente tiene que enumerar para obtener los resultados. No tiene forma de comprobar Conde etc. Lista es malo porque te expones demasiado control; el cliente puede añadir / eliminar de ella, etc., y que puede ser una cosa mala. Colección parece la mejor compromomise, al menos en opinión de FxCop. Me Allways uso lo que parece apropiado en mi contexto (por ejemplo. Si quiero devolver una única colección leer expongo colección como tipo de retorno y List.AsReadOnly () o IEnumerable de retorno para la evaluación perezosa a través del rendimiento, etc.). Llevarlo en una base de caso por caso

"aceptar el que menos puede, pero el regreso a la máxima de" es lo que yo defiendo.Cuando un método devuelve un objeto, ¿qué justificaciones tenemos para no devolver el tipo real y el límite de las capacidades del objeto mediante la devolución de un tipo base.Sin embargo, esto plantea una pregunta ¿cómo podemos saber lo que el "máximo" (de tipo real) será cuando el diseño de una interfaz.La respuesta es muy simple.Sólo en casos extremos en los que el diseñador de interfaz es el diseño de una interfaz abierta, la cual será ejecutada fuera de la aplicación/componente, ellos no saben lo que el rendimiento real puede ser.Una inteligente diseñador debe considerar siempre lo que el método debe hacer y lo que una óptima/genérico tipo de retorno debe ser.

E. g.Si estoy en el diseño de la interfaz para recuperar un vector de objetos, y sé que el recuento de objetos devueltos va a ser variable, siempre voy a asumir un smart desarrollador siempre use una Lista.Si alguien planes para devolver un Array, me gustaría cuestionar sus capacidades, a menos que él/ella sólo se devuelve los datos de otra capa que él/ella no propio.Y esta es probablemente la razón por la FxCop defensores de ICollection (base común para la Lista y Matriz).

El de arriba se dijo, hay un par de otras cosas a considerar

  • si los datos devueltos deben ser mutable o inmutable

  • si los datos devueltos ser compartida a través de múltiples personas que llaman

Con respecto a la LINQ perezoso evaluaciones estoy seguro de que el 95%+ C# los usuarios no entienden el intestacies.Es tan no-oo-ish.OO promueve concreto de los cambios de estado en las invocaciones del método.LINQ evaluación diferida promueve tiempo de ejecución de los cambios de estado en la evaluación de la expresión del patrón (no es algo de no-usuarios avanzados siga siempre).

Volviendo IEnumerable está bien si usted está realmente volviendo solamente una enumeración, y será consumida por la persona que llama como tal.

Pero, como otros señalan, tiene el inconveniente de que la persona que llama puede necesitar para enumerar si necesita cualquier otra información (por ejemplo, conde). El método de extensión .NET 3.5 IEnumerable .Count enumerará detrás de las escenas si el valor de retorno no implementa ICollection , que puede ser indeseable.

A menudo vuelvo IList o ICollection cuando el resultado es una colección - internamente el método puede utilizar un List y, o bien devolverlo tal cual, o volver List .AsReadOnly si querer proteger contra la modificación (por ejemplo, si estás almacenamiento en caché de la lista internamente). Que yo sepa FxCop es muy feliz con cualquiera de ellos.

Un aspecto importante es que cuando regrese un List<T> son reales devolver un referencia . Eso hace que sea posible que una persona que llama a manipular su lista. Este es un ejemplo de problemas para la común, una capa de negocios que devuelve un List<T> a una capa de interfaz gráfica de usuario.

El hecho de que usted dice que está volviendo IEnumerable no significa que no se puede devolver una lista. La idea es reducir el acoplamiento que no sean necesarios. Todo lo que la persona que llama debe preocuparse es conseguir una lista de las cosas, más que el tipo exacto de recogida utilizado para contener esa lista. Si usted tiene algo que está respaldado por una matriz, a continuación, obtener algo así como conde va a ser rápido de todos modos.

Creo su propia guía es grande - si usted es capaz de ser más específico acerca de lo que usted está volviendo sin impacto en el rendimiento (no se tiene que construir, por ejemplo, una lista de su resultado), que lo hagan. Pero si su función legítimamente no sabe qué tipo se va a encontrar, como si en algunas situaciones que va a trabajar con una lista y en algunas de ellas con una matriz, etc., entonces devolver IEnumerable es el "mejor" que puede hacer . Piense en ello como el "mayor común múltiplo" de todo lo que es posible que desee volver.

No puedo aceptar la respuesta elegida. Hay maneras de tratar con el escenario descrito, pero utilizando una lista o cualquier otra cosa que su uso no es uno de ellos. En el momento en el IEnumerable se devuelve usted tiene que asumir que la persona que llama puede hacer un foreach. En ese caso, no importa si el tipo de hormigón es de lista o espaguetis. De hecho, sólo la indexación es un problema, especialmente si los artículos se retiran.

Cualquier valor devuelto es una instantánea. Puede que sea el contenido actual de la IEnumerable en cuyo caso, si se almacena en caché que debería ser un clon de la copia en caché; si se supone que es más dinámico (como los resuts de una consulta SQL) a continuación, utilizar el retorno de rendimiento; Sin embargo permitiendo que el recipiente para mutar a voluntad y el suministro de métodos como el conde y indexador es una receta para el desastre en un mundo multiproceso. Ni siquiera he metido en la capacidad de la persona que llama para llamar Añadir o Eliminar en un recipiente de su código se supone que debe estar en control de.

También regresa un concreto tipo cerraduras que en una implementación. Hoy internamente que pueda estar usando una lista. Mañana tal vez usted no se convierta en multiproceso y desea utilizar un contenedor seguro para subprocesos o una matriz o una cola o la colección de valores de un diccionario o el resultado de una consulta LINQ. Si te encierras en un tipo concreto de retorno a continuación, usted tiene que cambiar, ya sea un montón de código o hacer unas conversiones antes de regresar.

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