Last active
June 21, 2018 03:28
-
-
Save rodrigolira/0c9afad48c823677e3e708ad03707b1e to your computer and use it in GitHub Desktop.
C# - Understanding unhandled exception on "async void" methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file simulates an event handler executing an async method. | |
// LoginAsync() throws an unhandled exception. The compiler generated code has no way to schedule a continuation for the Task. | |
// There isn't anyway it can signal a faulted state. We can't "await" LoginAsync() because the method doesn't return anything. | |
// To solve this problem, we can change LoginAsync signature, replacing "void" with "Task". | |
private void LoginButton_Click(object sender, EventArgs args) { | |
try { | |
LoginAsync(); | |
} catch (Exception) { | |
} | |
} | |
private async void LoginAsync() { | |
throw new UnauthorizedAccessException(); | |
try { | |
var result = await Task.Run(() => { | |
Thread.Sleep(2000); | |
return "Login successful!"; | |
}); | |
LoginButton.Text = result; | |
} catch (Exception) { | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Because the method now returns a Task, the application no longer throws an exception. | |
// Notice that the "catch" block in the event handler is not executed. That is because internally the exception is caught | |
// and then a faulted Task is returned. Because the Task is not awaited, there is no continuation context, which causes | |
// the exception not to be thrown. Notice that it's even possible to remove the "try..catch" block within the event handler. | |
// No exception will be thrown. | |
private void LoginButton_Click(object sender, EventArgs args) { | |
LoginAsync(); | |
} | |
private async Task LoginAsync() { | |
throw new UnauthorizedAccessException(); | |
try { | |
var result = await Task.Run(() => { | |
Thread.Sleep(2000); | |
return "Login successful!"; | |
}); | |
LoginButton.Text = result; | |
} catch (Exception) { | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Now the event handler is marked as async and LoginAsync is awaited. This means that the application | |
// will throw an exception when running and we can even catch it with a try..catch block. | |
private async void LoginButton_Click(object sender, EventArgs args) { | |
try { | |
await LoginAsync(); | |
} | |
catch (Exception) { | |
LoginButton.Text = "Login failed!"; | |
} | |
} | |
private async Task LoginAsync() { | |
throw new UnauthorizedAccessException(); | |
try { | |
var result = await Task.Run(() => { | |
Thread.Sleep(2000); | |
return "Login successful!"; | |
}); | |
LoginButton.Text = result; | |
} catch (Exception) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment