Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在catch条款中禁止等待。到处找工作_C#_Exception Handling_Async Await_C# 5.0 - Fatal编程技术网

C# 在catch条款中禁止等待。到处找工作

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

我知道wait不能用在catch子句中。 然而,直到现在,我还没有真正面对与此相关的问题

基本上,我有一个层,负责接收传入的请求,处理它们,从它们生成消息,并将消息传递给另一个负责发送消息的层

如果在发送消息的过程中出现问题,将抛出一个自定义异常,并由消息发送层捕获。此时,应该在DB中插入此消息的故障记录(需要一些时间,因此是异步的),并且应该将异常传播到上层,该层负责向发出请求的客户端发送错误响应

下面是一些非常简化的代码,用于下面的说明:

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!我会说我希望有一个更简单的方法来绕过这个,所以我没有像你在反射中走得那么远。但毕竟,没有简单的方法来处理这个问题;)不管怎样,非常感谢你的回答,我想我会走简单的路,但如果真的需要,至少我知道如何走“艰难”的路。