问题
I think there is something missing in my understanding. If I put a breakpoint in the catch where the Console.WriteLine
is done, it does not stop.
private static void Main(string[] args)
{
Process(async () => await ClientMethod()).Invoke();
Console.Read();
}
public static async Task ClientMethod()
{
throw new Exception("Test");
}
public static Action Process(Action functor)
{
return () =>
{
try
{
functor();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
throw;
}
};
}
But if I change my code into this, by removing the async behavior, the breakpoint is hit:
private static void Main(string[] args)
{
Process(() => ClientMethod()).Invoke();
Console.Read();
}
public static void ClientMethod()
{
throw new Exception("Test");
}
Why the exception is not caught in the first case? How can I catch it?
EDIT: I changed my code into this but it is still the same:
private static void Main(string[] args)
{
var res = Process(async () => await ClientMethod()).Invoke();
Console.Read();
}
public static async Task<string> ClientMethod()
{
throw new Exception("Test");
}
public static Func<T> Process<T>(Func<T> functor)
{
return () =>
{
try
{
return functor();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
throw;
}
};
}
回答1:
Because the action in Process is being invoked as an async void
.
Quote: from Async/Await - Best Practices in Asynchronous Programming
Async void methods have different error-handling semantics. When an exception is thrown out of an
async Task
orasync Task<T>
method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on theSynchronizationContext
that was active when the async void method started.
回答2:
The problem with your first code is that the Action
is causing an async void
method to be created. You should avoid async void for several reasons - one of which is that exception handling is odd (exceptions do not propagate from an async void
method in any kind of reasonable manner).
Your second code is odd. You can see more clearly what's going on if you remember that T
is Task<string>
. So, your wrapper delegate is just going to return a Task<string>
; it won't observe its exceptions. To observe exceptions from a task-returning method, you should await the task it returns, and the code in your try
block isn't await
ing the task - it's just returning it directly.
The solution is to go back to the first example. What you want to do is change the Action
delegate type to its asynchronous equivalent, which is Func<Task>. From here, the solution flows more naturally:
public static Func<Task> Process(Func<Task> functor)
{
return async () =>
{
try
{
await functor();
}
catch (Exception)
{
Console.WriteLine("In the catch");
throw;
}
};
}
Usage:
await Process(async () => await ClientMethod()).Invoke();
public static async Task ClientMethod()
{
throw new Exception("Test");
}
来源:https://stackoverflow.com/questions/41979621/why-is-the-exception-not-being-caught