「async void」イベントハンドラーを回避する必要がありますか?


118

async void保留中のタスクの追跡がなく、このようなメソッド内でスローされる可能性のある例外を処理するのが難しいため、タスクを開始するためにファイアアンドフォーゲットメソッドを使用することは、一般的に悪い考えと考えられます。

通常、async voidイベントハンドラーも回避する必要がありますか?例えば、

private async void Form_Load(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

次のように書き直すことができます。

Task onFormLoadTask = null; // track the task, can implement cancellation

private void Form_Load(object sender, System.EventArgs e)
{
        this.onFormLoadTask = OnFormLoadTaskAsync(sender, e);
} 

private async Task OnFormLoadTaskAsync(object sender, System.EventArgs e)
{
        await Task.Delay(2000); // do async work
        // ...
} 

再入可能性以外に、非同期イベントハンドラーの水中の岩は何ですか?


すべきですができません。その上、async voidを使用する際に注意が必要なことはすべて、UIイベントハンドラーですでに必要とされています。
Paulo Morgado 2013年

また、再入可能性は、イベントハンドラーによって起動される非同期操作のために発生し、それ自体でasync-awaitを使用するためではありません。
Paulo Morgado 2013年

回答:


152

ガイドラインは、イベントハンドラーで使用する場合async void を除いて回避するため、イベントハンドラーでの使用async voidは問題ありません。

とは言っても、ユニットテストの理由から、すべてのasync voidメソッドのロジックを除外することがよくあります。例えば、

public async Task OnFormLoadAsync(object sender, EventArgs e)
{
  await Task.Delay(2000);
  ...
}

private async void Form_Load(object sender, EventArgs e)
{
  await OnFormLoadAsync(sender, e);
}

気になります... Form_Loadのアクセス権を変更しないだけの理由はありますpublicか?コードはそのように冗長ではないようです。
InteXX、2015

おっと、気にしないでください... VBerがC#をここで読み込もうとしています...戻り値の型に気づきましたOnFormLoadAsync。これは便利なトリックになることがわかりました。ありがとう。
InteXX、2015

とはいえ、ここで一見して意見を述べていただけませんか。ありがとう!
InteXX、2015

2
@ AlexHopeO'Connor:Handledフラグ同期的に設定する必要あります。asyncイベントを処理するかどうかを決定するために使用することはできません。
Stephen Cleary

1
@ AlexHopeO'Connor:WPFアプリを使用してから久しぶりですが、以前と同様のソリューションを使用しました。つまり、ICommand.Executeメソッドを作成しasync voidます。ICommand.Execute論理的にはイベントハンドラなので、これは許容できると考えています。
Stephen Cleary

49

通常、非同期のvoidイベントハンドラーも回避する必要がありますか?

一般に、イベントハンドラーは、void asyncメソッドが潜在的なコードのにおいではない1つのケースです。

ここで、何らかの理由でタスクを追跡する必要がある場合、説明する手法は完全に合理的です。


6

はい、通常、イベントハンドラの非同期voidが唯一のケースです。詳細については、チャンネル9で素晴らしい動画をご覧ください。

The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".

ここにリンクがあります


トップレベルのイベントハンドラ」は重要なヒントです。下位レベルのイベントハンドラーで非同期voidイベントハンドラーを使用すると、キャッチされない例外で大きな問題が発生する可能性があります。
Portikus 2017年

ビデオリンクに感謝します。非常に便利です
lsp

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.