C# 在catch条款中禁止等待。到处找工作
我知道wait不能用在catch子句中。 然而,直到现在,我还没有真正面对与此相关的问题 基本上,我有一个层,负责接收传入的请求,处理它们,从它们生成消息,并将消息传递给另一个负责发送消息的层 如果在发送消息的过程中出现问题,将抛出一个自定义异常,并由消息发送层捕获。此时,应该在DB中插入此消息的故障记录(需要一些时间,因此是异步的),并且应该将异常传播到上层,该层负责向发出请求的客户端发送错误响应 下面是一些非常简化的代码,用于下面的说明:C# 在catch条款中禁止等待。到处找工作,c#,exception-handling,async-await,c#-5.0,C#,Exception Handling,Async Await,C# 5.0,我知道wait不能用在catch子句中。 然而,直到现在,我还没有真正面对与此相关的问题 基本上,我有一个层,负责接收传入的请求,处理它们,从它们生成消息,并将消息传递给另一个负责发送消息的层 如果在发送消息的过程中出现问题,将抛出一个自定义异常,并由消息发送层捕获。此时,应该在DB中插入此消息的故障记录(需要一些时间,因此是异步的),并且应该将异常传播到上层,该层负责向发出请求的客户端发送错误响应 下面是一些非常简化的代码,用于下面的说明: public async Task ProcessR
public async Task ProcessRequestAsync(Request req)
{
int statusCode = 0;
try
{
await SendMessageAsync(new Message(req));
}
catch(MyCustomException ex)
{
statusCode = ex.ErrorCode;
}
await SendReponseToClientAsync(req, statusCode);
}
public async Task SendMessageAsync(Message msg)
{
try
{
// Some async operations done here
}
catch (MyCustomException ex)
{
await InsertFailureForMessageInDbAsync(msg, ex.ErrorCode); // CAN'T DO THAT
throw;
}
}
当然,请求处理层对数据库一无所知,它只负责构建消息,将消息传递给消息处理层,并向客户机发送响应(肯定或否定)
所以我认为这是有道理的。。。如果发生异常,我的“业务”层希望在数据库中插入一条失败记录,并重新引发异常,以便“请求”处理层可以执行必要的操作(在这种情况下,将否定响应发送回客户端)
例外情况不应该这样使用吗?这对我来说似乎很干净,但事实上我不能在catch子句中等待这一点,这让我觉得设计中可能有一种代码味道(即使我想到在一个层中处理异常,然后重新调用它,让上层做一些不同的处理,我也觉得这正是异常的目的)
有什么想法吗
谢谢 我也遇到过几次这种情况 正如Rafael所评论的,您可以忽略InsertFailureFormessageAndBasync的结果:
public async Task SendMessageAsync(Message msg)
{
try
{
// Some async operations done here
}
catch (MyCustomException ex)
{
var _ = InsertFailureForMessageInDbAsync(msg, ex.ErrorCode);
throw;
}
}
请注意,InsertFailureForMessageInDbAsync
中的任何异常在默认情况下都将被忽略
您的另一个选项更为复杂:
public async Task DoSendMessageAsync(Message msg)
{
// Some async operations done here
}
public async Task SendMessageAsync(Message msg)
{
var task = DoSendMessageAsync(msg);
MyCustomException exception = null;
try
{
await task;
return;
}
catch (MyCustomException ex)
{
exception = ex;
}
await Task.WhenAll(task, InsertFailureForMessageInDbAsync(msg, exception.ErrorCode));
}
这将异步处理异常并返回一个具有实际聚合表达式的任务(如果InsertFailureFormessageAndBasync
抛出一个异常,则包含两个异常)
不幸的是,wait
将忽略第二个异常。如果确实希望传递所有异常,可以将最后一行(wait Task.whalll…
)替换为以下内容:
Exception exception2 = null;
try
{
await InsertFailureForMessageInDbAsync(msg, exception.ErrorCode);
}
catch (Exception ex)
{
exception2 = ex;
}
if (exception2 == null)
throw new AggregateException(exception);
else
throw new AggregateException(exception, exception2);
但这相当复杂,而且不完全是你想要重复的模式。如果可能的话,我会按照Rafael的建议忽略日志记录结果。似乎可以在发送层捕获异常,只需将状态对象返回给调用方。你甚至可以为这个状态对象创建一个类型为Exception
的字段,以便以后需要时可以重新抛出。你为什么不调用这个函数而不等待它呢?@dlev:谢谢你的想法,我仍然觉得在某个地方返回状态和在另一个地方使用Exception混合在一起不是很好。必须在返回状态代码(或对象)或抛出异常之间做出选择,但不能两者兼而有之(这是我从报告错误的“良好”设计指南中记得的)。@Rafael:我真的没有想到这一点。问题是,如果在InsertFailureForMessageInDbAsync调用期间发生异常,我将面临一个未被观察到的异常,这确实不好(不讨论避免警告的伪变量技巧),但这是一个好主意@Darky我承认这并不理想,我只是提供了一个允许一些灵活性的建议,考虑到使用wait
对您的限制。很好的Stephen!我会说我希望有一个更简单的方法来绕过这个,所以我没有像你在反射中走得那么远。但毕竟,没有简单的方法来处理这个问题;)不管怎样,非常感谢你的回答,我想我会走简单的路,但如果真的需要,至少我知道如何走“艰难”的路。