以下は、非同期を使用し、決して複数のスレッドを使用しないプログラムの例です。
public class Foo
{
private int _value;
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public int Value
{
get
{
return _value;
}
set
{
_value = value;
var oldTCS = tcs;
tcs = new TaskCompletionSource<bool>();
oldTCS.SetResult(true);
}
}
public Task ValueChanged()
{
return tcs.Task;
}
}
private static void Main(string[] args)
{
Foo foo = new Foo();
foo.ValueChanged()
.ContinueWith(t =>
{
Console.WriteLine(foo.Value);
}, TaskContinuationOptions.ExecuteSynchronously);
foo.Value = 5;
}
Task
返却元は、次に変更されたValueChanged
ときに完了しValue
ます。クラスのユーザーは、Foo
返されたタスクを取得し、まだ発生していない操作に基づいてそのタスクで実行する継続を結び付けることができます。その後、将来のある時点で の値foo
が変更され、継続が実行されます。foo オブジェクトは、 にはまったく知られていない他の関数に渡される可能性があることに注意してくださいMain
。
Task
を作成したり、継続を実行したりするために、新しいスレッドは必要ありません。
より実用的な別の例を次に示します。
Task
フォームを受け取り、そのフォームが次に閉じられたときに示すものを返すこの単純な (拡張) メソッドから始めます。
public static class FormExtensions
{
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<bool>();
form.FormClosed += (sender, args) => tcs.SetResult(true);
return tcs.Task;
}
}
これで、これをフォームの 1 つに含めることができます。
private async void button1_Click(object sender, EventArgs args)
{
Form2 otherForm = new Form2();
otherForm.Show();
await otherForm.WhenClosed();
//take some data from that form and display it on this form:
textBox1.Text = otherForm.Name;
}
別のフォームを作成して表示しても、新しいスレッドが作成されることはありません。このフォームと新しいフォームはどちらも、作成および変更する 1 つの UI スレッドを完全に使用します。
Task
返された fromの作成ではWhenClosed
、新しいスレッドを作成する必要はまったくありません。
待機Task
中は、新しいスレッドは作成されません。現在のメソッドは終了し、UI スレッドはメッセージの処理に戻ります。ある時点で、同じ UI スレッドが何かを実行し、2 番目のフォームが閉じられます。これにより、タスクの実行が継続され、テキスト ボックスのテキストを設定するボタン クリック ハンドラーに戻ります。
これはすべてUI スレッドで完全に行われ、他のスレッドは作成されていません。それでも、UI スレッドをブロックせずに、実行時間の長い操作 (ユーザーが 2 番目のフォームに情報を入力してから閉じる) が完了するのを (実際には待機せずに) 「待機」しただけなので、メイン フォームの応答性を維持できます。