C# 4.0 の悲しい時代に、IEnumerable の "yield return" 継続をハッキングしてオブザーバブルを待機することで、GUI スレッドで非同期ワークフローを許可する次の "WorkflowExecutor" クラスを作成しました。したがって、次のコードは、button1Click で、テキストを更新する単純なワークフローを開始し、button2 がクリックされるのを待って、1 秒後にループします。
public sealed partial class Form1 : Form {
readonly Subject<Unit> _button2Subject = new Subject<Unit>();
readonly WorkflowExecutor _workflowExecutor = new WorkflowExecutor();
public Form1() {
InitializeComponent();
}
IEnumerable<IObservable<Unit>> 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<Unit> WaitTimer(this IScheduler scheduler, double ms) {
return Observable.Timer(TimeSpan.FromMilliseconds(ms), scheduler).Select(_ => Unit.Default);
}
}
public sealed class WorkflowExecutor {
IEnumerator<IObservable<Unit>> _observables;
IDisposable _subscription;
public void Run(IEnumerable<IObservable<Unit>> actions) {
_observables = (actions ?? new IObservable<Unit>[0]).GetEnumerator();
Continue();
}
void Continue() {
if (_subscription != null) {
_subscription.Dispose();
}
if (_observables.MoveNext()) {
_subscription = _observables.Current.Subscribe(_ => Continue());
}
}
public void Stop() {
Run(null);
}
}
「yield」継続を使用して非同期作業を行うというアイデアのスマートな部分は、Daniel Earwickerの AsyncIOPipe アイデアから引用されました。return-of-lambdas/、その上にリアクティブ フレームワークを追加しました。
現在、C# 5.0 の async 機能を使用してこれを書き直すのに問題がありますが、それは簡単なことのようです。オブザーバブルをタスクに変換すると、一度だけ実行され、while ループが 2 回目にクラッシュします。それを修正する助けは素晴らしいでしょう。
言った/尋ねたすべてのことですが、async/await メカニズムによって、WorkflowExecutor では得られないものは何ですか? WorkflowExecutor では (同様の量のコードが与えられた場合) できないことで、async/await でできることはありますか?