Tengo la siguiente función para obtener errores de validación para una tarjeta. Mi pregunta se refiere a tratar con GetErrors. Ambos métodos tienen el mismo tipo de retorno IEnumerable<ErrorInfo>
.
private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
var errors = GetMoreErrors(card);
foreach (var e in errors)
yield return e;
// further yield returns for more validation errors
}
¿Es posible devolver todos los errores GetMoreErrors
sin tener que enumerarlos?
Pensar en esto probablemente sea una pregunta estúpida, pero quiero asegurarme de que no me estoy equivocando.
c#
ienumerable
yield
yield-return
John Oxley
fuente
fuente
GetCardProductionValidationErrorsFor
?Respuestas:
Definitivamente no es una pregunta estúpida, y es algo que F # admite con
yield!
una colección completa en comparaciónyield
con un solo elemento. (Eso puede ser muy útil en términos de recursión de cola ...)Lamentablemente no es compatible con C #.
Sin embargo, si tiene varios métodos, cada uno devuelve un
IEnumerable<ErrorInfo>
, puede usarEnumerable.Concat
para simplificar su código:Sin embargo, hay una diferencia muy importante entre las dos implementaciones: esta llamará a todos los métodos de inmediato , a pesar de que solo usará los iteradores devueltos uno a la vez. Su código existente esperará hasta que se repita todo
GetMoreErrors()
antes de que incluso le pregunte sobre los próximos errores.Por lo general, esto no es importante, pero vale la pena entender qué sucederá cuándo.
fuente
GetOtherErrors()
(etc.) están aplazando sus resultados (ya que se implementan utilizando bloques iteradores). Intente cambiarlos para devolver una nueva matriz o algo así, y verá lo que quiero decir.Puede configurar todas las fuentes de error como esta (nombres de métodos tomados de la respuesta de Jon Skeet).
Luego puede iterar sobre ellos al mismo tiempo.
Alternativamente, podría aplanar las fuentes de error con
SelectMany
.La ejecución de los métodos en
GetErrorSources
también se retrasará.fuente
Se me ocurrió un
yield_
fragmento rápido :Aquí está el fragmento XML:
fuente
yield!
, como en F #.No veo nada malo en tu función, diría que está haciendo lo que quieres.
Piense en el Rendimiento como que devuelve un elemento en la Enumeración final cada vez que se invoca, de modo que cuando lo tiene en el bucle foreach así, cada vez que se invoca devuelve 1 elemento. Tiene la capacidad de poner declaraciones condicionales en su foreach para filtrar el conjunto de resultados. (simplemente por no ceder en sus criterios de exclusión)
Si agrega rendimientos posteriores más adelante en el método, continuará agregando 1 elemento a la enumeración, haciendo posible hacer cosas como ...
fuente
Me sorprende que nadie haya pensado en recomendar un método de Extensión simple
IEnumerable<IEnumerable<T>>
para que este código mantenga su ejecución diferida. Soy fanático de la ejecución diferida por muchas razones, una de ellas es que la huella de memoria es pequeña incluso para enumerables enormes y monótonos.Y podrías usarlo en tu caso así
Del mismo modo, puede eliminar la función de envoltura
DoGetErrors
y simplemente pasarUnWrap
al sitio de llamadas.fuente
DoGetErrors(card).SelectMany(x => x)
hace lo mismo y conserva el comportamiento diferido. Que es exactamente lo que Adam sugiere en su respuesta .Sí, es posible devolver todos los errores a la vez. Solo devuelve un
List<T>
oReadOnlyCollection<T>
.Al devolver un
IEnumerable<T>
, estás devolviendo una secuencia de algo. En la superficie que puede parecer idéntica a la devolución de la colección, pero hay una serie de diferencias, debe tener en cuenta.Colecciones
Secuencias
IEnumerable<T>
permite una evaluación diferida, el retornoList<T>
no).fuente