2017-02-09 2 views
0

Im Wesentlichen das ich versuche, der Lage sein, zu tun:Ist es möglich, eine Liste asynchroner Elemente in einer asynchronen Methode von einer asynchronen Quelle zurückzugeben?

var thingTasks = thingFactory.GetMyThings(); 
// ... 
var things = await thingTasks; 

Ich versuche, aus einer Liste von Objekten zu beginnen, diese Liste durchlaufen für jeden einen async Anruf tätigen, und die Rückkehr des Satzes von Ergebnisse in einer await-Möglichkeit, so dass der Verbraucher wählen kann, wann zu await es. GetMyThings selbst verwendet await bevor die Liste zu erzeugen, so muss es async selbst und ist so etwas wie sein:

public async Task<List<Thing>> GetMyThings() { 
    var thingMakers = await GetThingMakers(); 
    var things = thingMakers.Select(async thing => await thing.GetAsync()); 
    return things; 
} 

Die Grundidee ist, dass ich einige await Linien haben, dann nach, dass ich die Ergebnisse dieser Linien verwenden, um eine Liste erstellen und jedes Element generieren erfordert auch einen async Aufruf. Ich versuche zu vermeiden, innerhalb der Methode zu blockieren (z. B. .Result) und stattdessen diese Verantwortung/Gelegenheit zurück an den Anrufer übergeben. Grundsätzlich starten Sie die Aufgaben in der Liste aber nicht await ihnen. Dies bringt mich natürlich dazu, Task<List<Thing>> oder 'List> `zurückgeben zu wollen.

Die nächstgelegene ich bekam, war return Task.WhenAll(things) aber das hat nicht funktioniert (es brauchte Task<Task<Thing[]>> und await await GetMyThings() sein. Alternativ return Select(...) ein Task<List<Task<Thing>>> Rückkehr und ein await Task.WhenAll(await GetMyThings()) auf der konsumierende Seite benötigen.

In beiden Fällen braucht man doppelt await Aussagen, die Liste zu erkennen. ich denke, es ist unmöglich, aber ist es eine Möglichkeit, die doppelte await zu vermeiden?

+2

'async Sache => erwarten thing.GetAsync()' 'ist nur Sache => thing.GetAsync() 'das ist auch das gleiche wie' GetAsync'. Kein unnötiges Umwickeln. – Servy

+0

Wenn Sie möchten, dass der Aufrufer die Ergebnisse nicht auspacken muss, lassen Sie die Ergebnisse von der Methode selbst entpacken, bevor Sie sie zurückgeben. Die Methode kann die Ergebnisse genau so entpacken, wie der Anrufer es getan hat. – Servy

Antwort

1

Verwenden Task.WhenAll alle Aufgaben auf einmal zu warten. auf diese Weise können sich GetAsync laufen in etwa auf dem gleichen Zeit. Also:

  1. Starten Sie alle Aufgabe
  2. Await alle
  3. Return Aufgabe der Ergebnisse

So:

public async Task<List<Thing>> GetMyThings() 
{ 
    var thingMakers = await GetThingMakers(); 
    var tasks = thingMakers.Select(thing => thing.GetAsync()); 
    var things = await Task.WhenAll(tasks); 
    return things.ToList(); 
} 
-1

Wenn Sie wollen, dass die inneren Aufgaben warten-Lage außerhalb machen , müssen Sie sie tatsächlich zurückgeben:

public async Task<List<Task<Thing>>> GetMyThings() { 
    var thingMakers = await GetThingMakers(); 
    var things = thingMakers.Select(thing => thing.GetAsync()); 
    return things.ToList(); 
} 

Anschließend können Sie diesen Aufruf wie folgt verwenden:

List<Task<Thing>> thingTasks = await GetMyThings(); 
await Task.WhenAll(thingTasks); 
List<Thing> = thingTasks.Select(t => t.Result).ToList(); 

Oder auch:

List<Thing> things = await GetMyThings() 
    .ContinueWith(async r => 
     { 
      await Task.WhenAll(r); 
      return r.Select(r => r.Result).ToList(); 
     }); 
Verwandte Themen