Итак, в печальные дни 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?