'async void'이벤트 핸들러를 피해야합니까?


119

async void작업을 시작 하기 위해 fire-and-forget 메서드 를 사용하는 것은 일반적으로 나쁜 생각으로 간주된다는 것을 알고 있습니다 . 대기중인 작업에 대한 추적이없고 그러한 메서드 내부에서 발생할 수있는 예외를 처리하는 것이 까다롭기 때문입니다.

일반적으로 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

그리고 재진입은 async-await 자체를 사용하는 것이 아니라 이벤트 핸들러에 의해 발생한 비동기 작업으로 인해 발생합니다.
— Paulo Morgado

답변:


153

가이드 라인은 이벤트 핸들러에서 사용하는 경우를 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

죄송합니다, 신경 쓰지 마세요 ... VBer가 여기서 C #을 읽으려고합니다 ... 방금 반환 유형이 OnFormLoadAsync. 나는 이것이 편리한 트릭을 만든다는 것을 알았다. 감사.
— InteXX

여기에서 한 번 살펴보고 의견을 제시해 주시겠습니까 ? 감사!
— InteXX

2
@ AlexHopeO'Connor : Handled플래그 는 동 기적으로 설정 되어야합니다 . async이벤트 처리 여부를 결정하는 데 사용할 수 없습니다.
— Stephen Cleary

2
@ AlexHopeO'Connor : WPF 앱으로 작업 한 지 오래되었지만 과거와 비슷한 솔루션을 사용했습니다. 즉, ICommand.Execute방법을 만드십시오 async void. 이후이 허용 생각 ICommand.Execute이다 논리적으로 이벤트 핸들러.
— Stephen Cleary

50

일반적으로 비동기 무효 이벤트 핸들러도 피해야합니까?

일반적으로 이벤트 핸들러는 void 비동기 메서드가 잠재적 인 코드 냄새가 아닌 경우입니다.

이제 어떤 이유로 작업을 추적해야하는 경우 설명하는 기술이 완벽하게 합리적입니다.


6

예, 일반적으로 이벤트 핸들러의 비동기 무효가 유일한 경우입니다. 그것에 대해 더 알고 싶다면 여기 채널 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".

여기에 링크가 있습니다


' 최상위 이벤트 처리자 '는 중요한 힌트입니다. 낮은 수준의 이벤트 처리기에서 async void 이벤트 처리기를 사용하면 예외가 발생하지 않는 큰 문제가 발생할 수 있습니다.
— Portikus 2011

비디오 링크 주셔서 감사합니다. 매우 유용합니다
— lsp

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.