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.
我认为我的理解中缺少一些东西。如果我在完成Console.WriteLine的catch中放置一个断点,它就不会停止。
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;
}
};
}
2 个解决方案
#1
3
Because the action in Process is being invoked as an async void
.
因为正在调用Process中的操作作为异步void。
Quote: from Async/Await - Best Practices in Asynchronous Programming
Quote:来自Async / Await - 异步编程的最佳实践
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.异步void方法具有不同的错误处理语义。当异步任务或异步Task
方法抛出异常时,将捕获该异常并将其放在Task对象上。使用async void方法,没有Task对象,因此异步void方法抛出的任何异常都将直接在异步void方法启动时处于活动状态的SynchronizationContext上引发。
#2
1
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).
您的第一个代码的问题是Action正在导致创建异步void方法。您应该避免异步void,原因有几个 - 其中一个原因是异常处理很奇怪(异常不会以任何合理的方式从异步void方法传播)。
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.
你的第二个代码很奇怪。如果你记得T是Task
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:
解决方案是回到第一个例子。您要做的是将Action委托类型更改为其异步等效项,即Func
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");
}
#1
3
Because the action in Process is being invoked as an async void
.
因为正在调用Process中的操作作为异步void。
Quote: from Async/Await - Best Practices in Asynchronous Programming
Quote:来自Async / Await - 异步编程的最佳实践
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.异步void方法具有不同的错误处理语义。当异步任务或异步Task
方法抛出异常时,将捕获该异常并将其放在Task对象上。使用async void方法,没有Task对象,因此异步void方法抛出的任何异常都将直接在异步void方法启动时处于活动状态的SynchronizationContext上引发。
#2
1
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).
您的第一个代码的问题是Action正在导致创建异步void方法。您应该避免异步void,原因有几个 - 其中一个原因是异常处理很奇怪(异常不会以任何合理的方式从异步void方法传播)。
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.
你的第二个代码很奇怪。如果你记得T是Task
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:
解决方案是回到第一个例子。您要做的是将Action委托类型更改为其异步等效项,即Func
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");
}