Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodrigolira/0c9afad48c823677e3e708ad03707b1e to your computer and use it in GitHub Desktop.
Save rodrigolira/0c9afad48c823677e3e708ad03707b1e to your computer and use it in GitHub Desktop.
C# - Understanding unhandled exception on "async void" methods
// 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) {
}
}
// 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) {
}
}
// 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