about exception of void return.
- 쉽게, sync에서 먼저.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
class asaw_4_sync { public void ThrowException() { throw new InvalidOperationException(); } public void SyncExceptions() { try { ThrowException(); } catch (Exception) { // The exception is never caught here! throw; } } } //////////////////////////////////////////////////// private void button1_Click(object sender, EventArgs e) { try { aa4s.SyncExceptions(); } catch (Exception ex) { textBox1.AppendText(ex.Message + Environment.NewLine); } }
- 예상 가능한 결과로
호출은 button event => SyncExceptions() => ThrowException() 으로,
Exceptions은 ThrowException() => SyncExceptions() => button event로
잘 타고 온다. 항상 보던 당연한 결말.
- 예상 가능한 결과로
- 위 방식을 async로 바꿔해본다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
class ASAW_4_async_1 { public async void ThrowException() { throw new InvalidOperationException(); } public void AsyncExceptions() { try { ThrowException(); } catch (Exception) { // The exception is never caught here! throw; } } } ////////////////// private void button2_Click(object sender, EventArgs e) { try { aa4a_1.AsyncExceptions(); } catch (Exception ex) { textBox1.AppendText(ex.Message + Environment.NewLine); } }
- 바뀐점은 ThrowException()가 async로 된것, 또 하지말라던 void로 한것.
- 호출은 button event => AsyncExceptions() => ThrowException()으로 동일,
Exception은 throw new InvalidOperationException(); 에서 멈춘다.
저 라인에서 throw를 못한다.
- 그럼 void가 아니라면??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
class ASAW_4_async_2 { public async Task ThrowException() { throw new InvalidOperationException(); } public void AsyncExceptions() { try { ThrowException(); } catch (Exception) { // The exception is never caught here! throw; } } } //////////////////////////////////////////////////////// private void button2_Click(object sender, EventArgs e) { try { aa4a_1.AsyncExceptions(); } catch (Exception ex) { textBox1.AppendText(ex.Message + Environment.NewLine); } }
- 위 ASAW_4_async_1과의 차이점은 void에서 Task가 된것.
- 호출 순서야 같은데 이번엔 throw new InvalidOperationException();에서
Exception도 안잡히고 끝난다. 아무런 반응이 없다. - 이 전 async/await_3 excention 1에서 말하는 The exception is never caught here!
은 Exception이 잡히건 말건 해당 try/catch는 절대 안들어온다는 뜻인것같다.
- 그럼 되는방법은?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
class ASAW_4_async_3 { //public async void ThrowException() //{ // throw new InvalidOperationException(); //} public async Task ThrowException() { throw new InvalidOperationException(); } public async void AsyncExceptions() { try { await ThrowException(); } catch (Exception) { // The exception is never caught here! throw; } } } /////////////////////////////////////////////////////////// private void button4_Click(object sender, EventArgs e) { try { aa4a_3.AsyncExceptions(); } catch (Exception ex) { textBox1.AppendText(ex.Message + Environment.NewLine); } }
- 다른점
- AsyncExceptions : async에 있어야할 await가 붙음
- async void를 그대로 하면 호출할때 에러남 async Task로 수정.
- 결과는 AsyncExceptions() 의 catch 부분에서 잡힌다.
- 따라서 정상적인 처리는 되는것처럼 보이는데
AsyncExceptions에서 button event로 throw는 안됨. 이 부분은 다시 button4_Click를 async void로 수정하고
aa4a_3.AsyncExceptions(); 호출을 await로 한다.
AsyncExceptions()도 async void에서 async Task로 수정.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
class ASAW_4_async_3 { //public async void ThrowException() //{ // throw new InvalidOperationException(); //} public async Task ThrowException() { throw new InvalidOperationException(); } public async Task AsyncExceptions() { try { await ThrowException(); } catch (Exception) { // The exception is never caught here! throw; } } } /////////////////////////////////////////////////////////// private async void button4_Click(object sender, EventArgs e) { try { await aa4a_3.AsyncExceptions(); } catch (Exception ex) { textBox1.AppendText(ex.Message + Environment.NewLine); } }
- 다른점
- 결과를 보면 async 함수들은 Task를 이용해 그 안에 정보를 넘기는듯하다.
근데 return이 Task니까 당연한건가 싶은데
data적인return 외에도 method적인 측면에서 실행 결과까지.
그래서 void return의 경우.. 넘길 수 없어서 그 선에서 끝내는건가?? 무튼 return되는 Task에는 Exception까지 있는것같은데 다시,
async/await_3 excention 2 의 Avoid Async Void 를 보면Async void 메서드는 오류 처리 의미가 다르다.
비동기 작업 또는 비동기 Task<T> 메서드에서 예외가 throw되면
해당 예외가 캡처되어 Task 개체에 배치함.
async void 메서드를 사용하면 Task 개체가 없으므로
async void 메서드에서 throw 된 모든 예외는
async void 메서드가 시작될 때 활성화 된 SynchronizationContext에서 직접 발생.
다음은 비동기 void 메서드에서 throw 된 exception을 catch못한 경우.이 말이 이제 이해가 감.
- 그럼 event를 제외하고 async void를 쓰지 말라했는데
exception의 최종 목적지이면 상관이 없어보임.
근데 이렇게 따지느니 Task로 도배하는게 맞는것같기도하고.. - 사실 async/await가 해주는 일이 더 많고
이것저것 더 볼게 많은것같은데 이거 찾으면서, 또는 이 관련해 더 많은건 아래.
Comments powered by Disqus.