我认为我的理解中缺少一些东西。如果我在Console.WriteLine
完成的捕获中放置一个断点,它就不会停止。
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;
}
};
}
但是如果我将代码更改为此代码,则通过删除异步行为,会触发断点:
private static void Main(string[] args)
{
Process(() => ClientMethod()).Invoke();
Console.Read();
}
public static void ClientMethod()
{
throw new Exception("Test");
}
为什么在第一种情况下没有发现异常?我怎么能抓住它?
编辑:我将代码更改为此内容但仍然相同:
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;
}
};
}
答案 0 :(得分:3)
因为正在调用进程中的操作async void
。
引用:来自Async/Await - Best Practices in Asynchronous Programming
Async void方法具有不同的错误处理语义。当一个 异常被抛出
async Task
或async Task<T>
方法 捕获异常并将其放在Task对象上。用async void 方法,没有Task对象,所以抛出任何异常 异步void方法将直接引发 异步void方法时处于活动状态的SynchronizationContext
启动。
答案 1 :(得分:1)
第一个代码的问题是Action
导致创建async void
方法。您应该avoid async void
有几个原因 - 其中一个原因是异常处理很奇怪(异常不会以任何合理的方式从async void
方法传播)。
你的第二个代码很奇怪。如果您记得T
是Task<string>
,您可以更清楚地看到正在发生的事情。所以,你的包装器委托只会返回一个Task<string>
;它不会遵守它的例外情况。 To observe exceptions from a task-returning method, you should await
the task it returns,try
块中的代码不是await
任务 - 它只是直接返回它。
解决方案是回到第一个例子。您要做的是将Action
委托类型更改为其异步等效项which is Func<Task>
。从这里开始,解决方案更自然地流动:
public static Func<Task> Process(Func<Task> functor)
{
return async () =>
{
try
{
await functor();
}
catch (Exception)
{
Console.WriteLine("In the catch");
throw;
}
};
}
用法:
await Process(async () => await ClientMethod()).Invoke();
public static async Task ClientMethod()
{
throw new Exception("Test");
}