ここで混乱していることがいくつかあると思います。何を求めていることである、すでに使用可能System.Threading.Tasks
、async
およびawait
C#5には、ちょうど同じ機能のために少しよりよい構文糖を提供しようとしています。
Winformsの例を使用してみましょう-フォームにボタンとテキストボックスをドロップし、次のコードを使用します。
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
.ContinueWith(t => DelayedAdd(t.Result, 20))
.ContinueWith(t => DelayedAdd(t.Result, 30))
.ContinueWith(t => DelayedAdd(t.Result, 50))
.ContinueWith(t => textBox1.Text = t.Result.ToString(),
TaskScheduler.FromCurrentSynchronizationContext());
}
private int DelayedAdd(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
実行すると、(a)UIスレッドがブロックされず、(b)通常の「スレッド間操作が無効です」というエラーが表示されません- TaskScheduler
最後の引数を削除しない限りContinueWith
、どの場合になります。
これは、湿地標準の継続渡しスタイルです。魔法はTaskScheduler
クラス、特にによって取得されたインスタンスで発生しますFromCurrentSynchronizationContext
。これを継続に渡すと、FromCurrentSynchronizationContext
メソッドを呼び出したスレッド(この場合はUIスレッド)で継続を実行する必要があることを伝えます。
ウェイターは、開始したスレッドと継続を実行する必要のあるスレッドを認識しているという意味で、わずかに洗練されています。したがって、上記のコードはもう少し自然に書くことができます。
private async void button1_Click(object sender, EventArgs e)
{
int a = await DelayedAddAsync(5, 10);
int b = await DelayedAddAsync(a, 20);
int c = await DelayedAddAsync(b, 30);
int d = await DelayedAddAsync(c, 50);
textBox1.Text = d.ToString();
}
private async Task<int> DelayedAddAsync(int a, int b)
{
Thread.Sleep(500);
return a + b;
}
これら二つは非常に似ているはずですし、実際に彼らはある非常に似ています。DelayedAddAsync
方法について返しTask<int>
の代わりにint
、そのためawait
だけのもののそれぞれに継続を叩きされます。主な違いは、各行で同期コンテキストを渡すことです。したがって、前の例で行ったように明示的に行う必要はありません。
理論的には、違いははるかに重要です。2番目の例では、button1_Click
メソッドのすべての行が実際にUIスレッドで実行されますが、タスク自体(DelayedAddAsync
)はバックグラウンドで実行されます。最初の例では、UIスレッドの同期コンテキストに明示的にアタッチした割り当てを除き、すべてがバックグラウンドで実行されます。textBox1.Text
それは本当に興味深いことですawait
-待機者がブロッキング呼び出しなしで同じメソッドに出入りできるという事実。あなたは、呼び出しawait
、現在のスレッドがバックメッセージの処理に移行し、それが終了したとき、それがでオフに左に同じスレッドで、中断したところ、awaiterは正確にピックアップします。しかし、あなたの面でInvoke
/のBeginInvoke
「私は、問題のコントラストずいぶん前にそれをやめるべきだったと言って申し訳ありません。
await
機能性に関する限り、これは非常にありそうにないようです。これは、継続の受け渡しのための単なる構文上の砂糖です。おそらく、WinFormsに関係のない他の改善点がいくつかありますが、それらは役立つはずです ただし、これは.NETフレームワーク自体に該当し、C#には該当しません。