ожидание на наблюдаемом

Итак, в печальные дни C #4.0 я создал следующий класс «WorkflowExecutor», который разрешал асинхронные рабочие процессы в потоке GUI, взломав продолжения «yield return» IEnumerable для ожидания наблюдаемых. Таким образом, следующий код в button1Click просто запускает простой рабочий процесс, который обновляет текст, ждет, пока вы нажмете кнопку button2, и зацикливается через 1 секунду.

public sealed partial class Form1 : Form {
    readonly Subject _button2Subject = new Subject();
    readonly WorkflowExecutor _workflowExecutor = new WorkflowExecutor();

    public Form1() {
        InitializeComponent();
    }

    IEnumerable> CreateAsyncHandler() {
        Text = "Initializing";
        var scheduler = new ControlScheduler(this);
        while (true) {
            yield return scheduler.WaitTimer(1000);
            Text = "Waiting for Click";
            yield return _button2Subject;
            Text = "Click Detected!";
            yield return scheduler.WaitTimer(1000);
            Text = "Restarting";
        }
    }

    void button1_Click(object sender, EventArgs e) {
        _workflowExecutor.Run(CreateAsyncHandler());
    }

    void button2_Click(object sender, EventArgs e) {
        _button2Subject.OnNext(Unit.Default);
    }

    void button3_Click(object sender, EventArgs e) {
        _workflowExecutor.Stop();
    }
}

public static class TimerHelper {
    public static IObservable WaitTimer(this IScheduler scheduler, double ms) {
        return Observable.Timer(TimeSpan.FromMilliseconds(ms), scheduler).Select(_ => Unit.Default);
    }
}

public sealed class WorkflowExecutor {
    IEnumerator> _observables;
    IDisposable _subscription;

    public void Run(IEnumerable> actions) {
        _observables = (actions ?? new IObservable[0]).GetEnumerator();
        Continue();
    }

    void Continue() {
        if (_subscription != null) {
            _subscription.Dispose();
        }
        if (_observables.MoveNext()) {
            _subscription = _observables.Current.Subscribe(_ => Continue());
        }
    }

    public void Stop() {
        Run(null);
    }
}

Умная часть идеи, использующая продолжения "yield" для выполнения асинхронной работы, была взята из идеи AsyncIOPipe Дэниела Эрвикера :http://smellegantcode.wordpress.com/2008/12/05/asynchronous-sockets-with-yield-return-of-lambdas/, затем я добавил к ней реактивный фреймворк.

Теперь у меня возникли проблемы с переписыванием этого с использованием асинхронной функции в C #5.0, но кажется, что это должно быть просто. Когда я конвертирую наблюдаемые в задачи, они запускаются только один раз, а цикл while дает сбой во второй раз. Любая помощь в исправлении этого была бы замечательной.

Все, что было сказано/спрошено, что дает мне механизм async/await, чего не дает WorkflowExecutor? Есть ли что-то, что я могу сделать с помощью async/await, чего я не могу просто сделать (, учитывая аналогичный объем кода )с WorkflowExecutor?

21
задан Dax Fohl 24 April 2012 в 00:49
поделиться