Tarefa do iterador asynchronous <IEnumerable >

Estou tentando implementar uma function assíncrona que retorna um iterador. A ideia é a seguinte:

private async Task<IEnumerable> TestAsync(string testString) { foreach (char c in testString.ToCharArray()) { // do other work yield return c; } } 

No entanto, há uma mensagem de erro que a function não pode ser um bloco iterador porque a Task<IEnumerable> não é um tipo de interface do iterador. Há uma solução?

Parece que o que você pode realmente estar procurando é algo como IObservable , que é como um IEnumerable asynchronous baseado em push IEnumerable . Veja Reative Extensions, também conhecido como Rx da Microsoft Open Technologies (código licenciado sob Apache-2.0) (sem afiliação) para uma grande quantidade de methods que funcionam com o IObservable para que ele funcione como o LINQ-to-Objects e muito mais.

O problema com IEnumerable é que não há nada que realmente faz a enumeração em si assíncrona. Se você não quiser adicionar uma dependência no Rx (que é realmente o que faz o IObservable brilhar), essa alternativa pode funcionar para você:

 public async Task> TestAsync(string testString) { return GetChars(testString); } private static IEnumerable GetChars(string testString) { foreach (char c in testString.ToCharArray()) { // do other work yield return c; } } 

Embora eu gostaria de salientar que, sem saber o que realmente está sendo feito de forma assíncrona, pode haver uma maneira muito melhor para alcançar seus objectives. Nenhum dos códigos que você postou realmente faz algo de forma assíncrona, e eu realmente não sei se alguma coisa em // do other work é assíncrona (nesse caso, isso não é uma solução para seu problema subjacente, embora ele faça seu código compilar).

Para elaborar respostas anteriores, você pode usar a família de methods Observable.Create das Reativas Extensões para fazer exatamente o que você quer.

Aqui está um exemplo:

 var observable = Observable.Create(async (observer, cancel) => { for (var i = 0; !cancel.IsCancellationRequested && i < 100; i++) { observer.OnNext(await GetCharAsync()); } }); 

Veja como você pode usá-lo no LINQPad, por exemplo:

 // Create a disposable that keeps the query running. // This is necessary, since the observable is 100% async. var end = Util.KeepRunning(); observable.Subscribe( c => Console.WriteLine(c.ToString()), () => end.Dispose()); 

Uma implementação mais “incluída em baterias” desse tipo de coisa, incluindo suporte a idiomas, está atualmente (no momento em que escrevo) sendo considerada para inclusão no C # 8.0.

Pelo que entendi, isso está sujeito a alterações a qualquer momento.