2014-04-25 21 views
20

Ich versuche eine asynchrone Funktion zu implementieren, die einen Iterator zurückgibt. Die Idee ist folgende:Asynchroner Iterator Aufgabe <IEnumerable <T>>

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

Allerdings gibt es eine Fehlermeldung, dass die Funktion nicht ein Iteratorblock sein kann, weil Task<IEnumerable<char>> kein Iterator Interface-Typ ist. Gibt es eine Lösung?

+4

Beachten Sie, dass dies nur besagt, dass * das Aufzählungszeichen an erster Stelle * asynchron ist - es macht es nicht zu einem asynchronen Enumerator. Was willst du eigentlich machen? Weil ich vermute, dass dies nicht erreicht wird. –

+3

Überprüfen Sie http://asyncenum.codeplex.com/ – daryal

+0

Ich möchte diese Funktion ausführen, um mit einem Stream in einem Worker-Thread zu arbeiten und das erwartete Ergebnis im UI-Thread zu verarbeiten. – user2341923

Antwort

13

Es klingt wie, was Sie wirklich suchen können, ist so etwas wie IObservable<T>, die eine Art von Push-basierte asynchrone IEnumerable<T> ist. Siehe Reactive Extensions, a.k.a. Rx von Microsoft Open Technologies (Code unter Apache-2.0 lizenziert) (keine Zugehörigkeit) für eine große Anzahl von Methoden, die mit IObservable<T> arbeiten, damit es wie LINQ-to-Objects und mehr funktioniert.

Das Problem mit IEnumerable<T> ist, dass es nichts gibt, das wirklich die Enumeration selbst asynchron macht. Wenn Sie nicht eine Abhängigkeit von Rx hinzufügen möchten (was wirklich ist, was IObservable<T> Glanz macht), könnte diese Alternative für Sie arbeiten:

public async Task<IEnumerable<char>> TestAsync(string testString) 
{ 
    return GetChars(testString); 
} 

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

obwohl ich möchte darauf hinweisen, dass, ohne zu wissen, was eigentlich asynchron durchgeführt wird, gibt es möglicherweise einen viel besseren Weg, um Ihre Ziele zu erreichen. Keiner der von Ihnen geposteten Code wird tatsächlich asynchron tun, und ich weiß nicht wirklich, ob irgendetwas in // do other work asynchron ist (in diesem Fall ist dies keine Lösung für Ihr zugrunde liegendes Problem, obwohl es Ihren Code kompilieren wird).

9

Um auf frühere Antworten näher einzugehen, können Sie die Methodenfamilie Observable.Create<TResult> von Reactive Extensions verwenden, um genau das zu tun, was Sie wollen.

Hier ist ein Beispiel:

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

Hier ist, wie Sie es in LINQPad verwenden können, zum Beispiel:

// 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()); 
Verwandte Themen