138 votes

Est-il possible de "await yield return DoSomethingAsync()" ?

Les blocs itérateurs ordinaires (c'est-à-dire "yield return") sont-ils incompatibles avec "async" et "await" ?

Cela donne une bonne idée de ce que j'essaie de faire :

async Task<IEnumerable<Foo>> Method(String [] Strs)
{
    // I want to compose the single result to the final result, so I use the SelectMany
    var finalResult = UrlStrings.SelectMany(link =>   //i have an Urlstring Collection 
                   await UrlString.DownLoadHtmlAsync()  //download single result; DownLoadHtmlAsync method will Download the url's html code 
              );
     return finalResult;
}

Cependant, j'obtiens une erreur du compilateur citant "unable to load message string from resources".

Voici une autre tentative :

async Task<IEnumerable<Foo>> Method(String [] Strs)
{
    foreach(var str in strs)
    {
        yield return await DoSomethingAsync( str)
    }
}

Mais là encore, le compilateur renvoie une erreur : "unable to load message string from resources".


Voici le code de programmation réel de mon projet

C'est très utile lorsque j'ai une liste de tâches, cette tâche peut être téléchargée en HTML à partir d'une URL. et que j'utilise la syntaxe "yield return await task", le résultat est que je veux IEnumerable<Foo> . Je ne veux pas écrire ce code :

async Task<IEnumerable<String>> DownLoadAllURL(String [] Strs)
{
    List<Foo> htmls= new ...
    foreach(var str in strs)
    {
        var html= await DownLoadHtmlAsync( str)
        htmls.Add(item)
    }
    return htmls;
}

Mais il semble que je doive le faire.

Merci de votre aide.

5voto

Thaina Yu Points 1258

Il y avait un plan pour faire

https://github.com/dotnet/csharplang/issues/43

Mais actuellement, ce n'est pas possible

Mise à jour : Il a été ajouté dans C# 8.0

1voto

John Gietzen Points 23645

Tout d'abord, gardez à l'esprit que la partie Async n'est pas terminée. L'équipe C# a encore un long chemin à parcourir avant la sortie de C# 5.

Ceci étant dit, je pense que vous voudrez peut-être rassembler les tâches qui sont lancées dans le fichier DownloadAllHtml de manière différente.

Par exemple, vous pouvez utiliser quelque chose comme ceci :

IEnumerable<Task<string>> DownloadAllUrl(string[] urls)
{
    foreach(var url in urls)
    {
        yield return DownloadHtmlAsync(url);
    }
}

async Task<string> DownloadHtmlAsync(url)
{
    // Do your downloading here...
}

Non pas que le DownloadAllUrl est PAS un appel asynchrone. Mais l'appel asynchrone peut être implémenté dans une autre fonction (c.-à-d. DownloadHtmlAsync ).

La bibliothèque de tâches parallèles dispose de la fonction .ContinueWhenAny y .ContinueWhenAll fonctions.

Cela peut être utilisé de la manière suivante :

var tasks = DownloadAllUrl(...);
var tasksArray = tasks.ToArray();
var continuation = Task.Factory.ContinueWhenAll(tasksArray, completedTasks =>
{
    completedtask
});
continuation.RunSynchronously();

1voto

Johan Franzén Points 1164

Yield ne fonctionne pas avec await, malheureusement. Mais c'est à cela que sert Rx. Voir https://msdn.microsoft.com/library/hh242985

-1voto

Francois Points 181

Cette solution fonctionne comme prévu. Notez que les await Task.Run(() => enumerator.MoveNext()) partie.

using (var enumerator = myEnumerable.GetEnumerator())
{
    while (true)
    {
        if (enumerator.Current != null)
        {
            //TODO: do something with enumerator.Current
        }

        var enumeratorClone = monitorsEnumerator;
        var hasNext = await Task.Run(() => enumeratorClone.MoveNext());
        if (!hasNext)
        {
            break;
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X