Eu tenho a seguinte função para obter erros de validação para um cartão. Minha pergunta diz respeito a lidar com GetErrors. Ambos os métodos têm o mesmo 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
}
É possível retornar todos os erros GetMoreErrors
sem precisar enumerá-los?
Pensar nisso provavelmente é uma pergunta estúpida, mas quero ter certeza de que não estou errado.
c#
ienumerable
yield
yield-return
John Oxley
fonte
fonte
GetCardProductionValidationErrorsFor
?Respostas:
Definitivamente, não é uma pergunta estúpida, e é algo que o F # suporta
yield!
para uma coleção inteira versusyield
um único item. (Isso pode ser muito útil em termos de recursão da cauda ...)Infelizmente, não há suporte para C #.
No entanto, se você tiver vários métodos, cada um retornando um
IEnumerable<ErrorInfo>
, poderá usarEnumerable.Concat
para tornar seu código mais simples:Porém, existe uma diferença muito importante entre as duas implementações: esta chamará todos os métodos imediatamente , mesmo que use apenas os iteradores retornados um de cada vez. Seu código existente aguardará até que ele repita tudo
GetMoreErrors()
antes de perguntar sobre os próximos erros.Geralmente isso não é importante, mas vale a pena entender o que acontecerá quando.
fonte
GetOtherErrors()
(etc) estão adiando seus resultados (como eles são implementados usando blocos iteradores). Tente alterá-los para retornar uma nova matriz ou algo assim, e você verá o que quero dizer.Você pode configurar todas as fontes de erro como esta (nomes de métodos emprestados da resposta de Jon Skeet).
Você pode iterar sobre eles ao mesmo tempo.
Como alternativa, você pode achatar as fontes de erro com
SelectMany
.A execução dos métodos
GetErrorSources
também será atrasada.fonte
Eu vim com um
yield_
trecho rápido :Aqui está o XML do trecho:
fonte
yield!
, como em F #.Não vejo nada de errado com sua função, eu diria que está fazendo o que você deseja.
Pense no Yield como retornando um elemento na Enumeração final toda vez que for chamado, portanto, quando você o tiver no loop foreach assim, toda vez que for chamado, ele retornará 1 elemento. Você tem a capacidade de colocar instruções condicionais em seu foreach para filtrar o conjunto de resultados. (simplesmente não cumprindo seus critérios de exclusão)
Se você adicionar rendimentos subsequentes posteriormente no método, ele continuará adicionando 1 elemento à enumeração, possibilitando fazer coisas como ...
fonte
Estou surpreso que ninguém tenha pensado em recomendar um método simples de extensão
IEnumerable<IEnumerable<T>>
para fazer esse código manter sua execução adiada. Sou fã de execução adiada por muitas razões, uma delas é que a pegada de memória é pequena, mesmo para enumeráveis enormes.E você pode usá-lo no seu caso como este
Da mesma forma, você pode acabar com a função de invólucro
DoGetErrors
e simplesmente mudarUnWrap
para o local da chamada.fonte
DoGetErrors(card).SelectMany(x => x)
faz o mesmo e preserva o comportamento adiado. O que é exatamente o que Adam sugere em sua resposta .Sim, é possível retornar todos os erros de uma só vez. Basta retornar um
List<T>
ouReadOnlyCollection<T>
.Ao retornar um,
IEnumerable<T>
você está retornando uma sequência de algo. Na superfície, isso pode parecer idêntico ao retorno da coleção, mas há várias diferenças, você deve ter em mente.Colecções
Sequências
IEnumerable<T>
permite uma avaliação lenta, o retornoList<T>
não).fonte