私は非同期プログラミングが初めてなので、いくつかの非同期サンプルコードを調べた後、簡単な非同期コードを書くことを考えました
簡単なWinformアプリケーションを作成し、フォーム内に次のコードを記述しました。しかし、それはただ動いていない
private Task<string> methodAsync() {
Thread.Sleep(10000);
return "Hello"; //Error: Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
}
private async void button1_Click(object sender, EventArgs e)
{
string s = await methodAsync();
MessageBox.Show(s);
}
誰かがここに光を当ててください。
リストされているメソッドの戻り値の型はTask<string>
です。 string
を返そうとしています。これらは同じではなく、文字列からTask<string>
への暗黙的な変換も存在しないため、エラーが発生します。
おそらく、戻り値がコンパイラによってasync
に自動的にラップされるTask
メソッドとこれを混同している可能性があります。現在、このメソッドは非同期メソッドではありません。あなたはほぼ確実にこれを行うつもりでした:
private async Task<string> methodAsync()
{
await Task.Delay(10000);
return "Hello";
}
2つの重要な変更点があります。まず、メソッドはasync
としてマークされます。これは、戻り値の型がTask
でラップされ、メソッドがコンパイルされることを意味します。次に、ブロッキング待機を行いたくありません。一般的なルールとして、await
モデルを使用する場合、可能な場合は待機をブロックしないようにしてください。 Task.Delay
は、指定されたミリ秒数後に完了するタスクです。そのタスクをawait
- ingすることで、その時間の間、非ブロッキング待機を効果的に実行します(実際には、メソッドの残りはそのタスクの継続です)。
await
を使用せずに4.0の方法を好む場合、これを行うことができます。
private Task<string> methodAsync()
{
return Task.Delay(10000)
.ContinueWith(t => "Hello");
}
最初のバージョンは多かれ少なかれこのようなものにコンパイルされますが、エラー処理やその他のawait
の機能をサポートするための追加の定型コードがあります。
しばらく待機するのではなく、Thread.Sleep(10000)
が実際に長時間実行されるメソッドのプレースホルダーになることを意図している場合は、代わりに別のスレッドで作業が行われるようにする必要があります。現在のコンテキストの。これを行う最も簡単な方法は、Task.Run
を使用することです。
private Task<string> methodAsync()
{
return Task.Run(()=>
{
SomeLongRunningMethod();
return "Hello";
});
}
またはより可能性が高い:
private Task<string> methodAsync()
{
return Task.Run(()=>
{
return SomeLongRunningMethodThatReturnsAString();
});
}
FromResultメソッドを使用
public async Task<string> GetString()
{
System.Threading.Thread.Sleep(5000);
return await Task.FromResult("Hello");
}
@Servyによって指摘されたasync
の問題のある使用を超えて、他の問題は、Task.Resultを呼び出してTask<T>
からT
を明示的に取得する必要があることです。 Resultプロパティは非同期コードをブロックするため、注意して使用する必要があることに注意してください。
試してください:
private async void button1_Click(object sender, EventArgs e)
{
var s = await methodAsync();
MessageBox.Show(s.Result);
}