120

シンプルな wpf デスクトップ アプリケーションを作成しています。UI には、.cs ファイルのようなボタンとコードだけがあります。

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    FunctionA();
}

public void FunctionA()
{
    Task.Delay(5000).Start();
    MessageBox.Show("Waiting Complete");
}

しかし、驚くべきことに、行Task.Delay(5000).Start();InvalidOperationException:

Promise スタイルのタスクで Start を呼び出すことはできません。

なぜこのようになっているのか、誰か助けてもらえますか?

4

1 に答える 1

193

Taskクラスがタスクを提供する前にすでにタスクを開始しているため、このエラーが発生します。コンストラクターを呼び出すことによって作成したタスクのみを呼び出すStart必要があります。作成時にタスクを開始しないというやむを得ない理由がない限り、それを行うべきではありません。すぐに開始したい場合は、を使用するTask.RunTask.Factory.StartNew、新しいを作成して開始する必要がありますTask

だから、今、私たちはその厄介なものを取り除くことを知っていStartます。コードを実行すると、メッセージボックスが5秒後ではなく、すぐに表示されることがわかります。どうしたのでしょうか。

さて、Task.Delay5秒で完了するタスクを提供します。スレッドの実行を5秒間停止しません。あなたがしたいのは、そのタスクが終了した後に実行されるいくつかのコードを持っていることです。それContinueWithが目的です。特定のタスクが完了した後、いくつかのコードを実行できます。

public void FunctionA()
{
    Task.Delay(5000)
    .ContinueWith(t => 
    {
        MessageBox.Show("Waiting Complete");
    });
}

これは期待どおりに動作します。

また、C#5.0のawaitキーワードを活用して、継続をより簡単に追加することもできます。

public async Task FunctionA()
{
    await Task.Delay(5000);
    MessageBox.Show("Waiting Complete");
}

ここで何が起こっているかについての完全な説明はこの質問の範囲を超えていますが、最終結果は前の方法と非常によく似た動作をする方法です。メソッドを呼び出してから5秒後にメッセージボックスが表示されますが、どちらの場合も、メソッド自体は[ほぼ]すぐに返されます。とは言うawaitものの、非常に強力であり、単純でわかりやすいように見えるメソッドを作成できますが、ContinueWith直接使用して作成するのははるかに難しく、面倒です。また、エラー処理の処理が大幅に簡素化され、多くの定型コードが削除されます。

于 2013-03-01T21:34:12.620 に答える