【问题标题】:Is General Exception handling not so bad in this case? [closed]在这种情况下,一般异常处理不是那么糟糕吗? [关闭]
【发布时间】:2019-08-21 09:04:39
【问题描述】:

在下面的代码中,我尝试发送一组通知,我想知道通知是否发送成功(稍后将其放入数据库中,因此不再发送)。

我在这里抓到Exception 是不是很糟糕?我真的不在乎未发送通知的原因。

private static async Task<List<Tuple<NotificationToSend, bool>>> SendNotificationsAsync(IEnumerable<NotificationToSend> notificationsToSend)
{
    var tuples = new List<Tuple<NotificationToSend, bool>>();

    using (var smtpClient = new SmtpClient())
    {
        foreach (var notification in notificationsToSend)
        {
            bool sentSuccessfully;

            try
            {
                var mailMessage = new MailMessage
                {
                    Subject = notification.Subject,
                    Body = $"{notification.Text} <br /> This notification was sent automatically",
                    IsBodyHtml = true
                };

                mailMessage.To.Add(notification.ToEmail);

                await smtpClient.SendMailAsync(mailMessage);
                sentSuccessfully = true;
            }
            catch (Exception e)
            {
                sentSuccessfully = false;
                // Here I also plan to log the exception
            }

            var tuple = new Tuple<NotificationToSend, bool>(notification, sentSuccessfully);
            tuples.Add(tuple);
        }
    }

    return tuples;
}

【问题讨论】:

  • “这真的很糟糕吗”非常基于意见,不是吗?不可能在这里发布“正确”或“错误”的答案。
  • 你的 try 块可以更小,但你只需要 await smtpClient.SendMailAsync(mailMessage);sentSuccessfully = true;
  • @ZoharPeled 如果notification 为空怎么办?
  • 你真的想抓住NullReferenceException吗?
  • @ZoharPeled 不是。我不想抓住任何东西。我只是想看看通知是否发送成功。

标签: c# .net exception .net-4.0


【解决方案1】:

你永远不应该使用catch(Exception e),你应该只捕获你知道可以抛出的异常。并且使用 SmtpClient the MSDN documentation 表示可以抛出以下四个异常之一:

所以你应该这样做:

var sentSuccessfully = false;

var mailMessage = new MailMessage
{
    Subject = notification.Subject,
    Body = $"{notification.Text} <br /> This notification was sent automatically",
    IsBodyHtml = true
};

MailMessage.To.Add(notification.ToEmail);

try
{
    await smtpClient.SendMailAsync(mailMessage);
    sentSuccessfully = true;
}
catch (ArgumentNullException e)
{
    sentSuccessfully = false;
    // Handle Argument Exception
}
catch (InvalidOperationException e)
{
    sentSuccessfully = false;
    // Handle InvalidOperation Exception
}
catch (ObjectDisposedException e)
{
    // This one shouldn't happen, so you could leave it out
    sentSuccessfully = false;
    // Do Handle ObjectDisposed Exception
}
catch (SmtpException e)
{
    sentSuccessfully = false;
    // Handle Smtp Exception
}

这样做的原因是更好的日志记录,如果您知道引发的异常,日志可能会显示类似“ArgumentNullException was throw, *insert a possible explanation for why*”

或者如果您想以相同的方式处理所有异常:

try
{
    await smtpClient.SendMailAsync(mailMessage);
    sentSuccessfully = true;
}
catch (Exception e) when (e is ArgumentNullException || 
    e is InvalidOperationException || 
    e is ObjectDisposedException || 
    e is SmtpException)
{
    sentSuccessfully = false;
    // Handle exception
}

【讨论】:

    【解决方案2】:

    取决于您想要实现的行为。 即使有人在 try...catch 中引入了诸如空引用之类的直截了当的错误,像这样的一揽子捕获也会使程序“跛行”。通常这是不希望的,最好快速失败。

    如果您希望程序仅在“预期”的 SMTP 基础结构错误之后继续运行,则仅捕获特定类型的异常(例如 SmtpException 或 SendMailAsync 可能引发的任何异常),否则让异常冒泡。

    【讨论】:

      【解决方案3】:

      我的目标:

      private static async Task<List<Tuple<NotificationToSend, bool>>> SendNotificationsAsync(IEnumerable<NotificationToSend> notificationsToSend)
      {
          var tuples = new List<Tuple<NotificationToSend, bool>>();
      
          using (var smtpClient = new SmtpClient())
          {
              foreach (var notification in notificationsToSend)
              {
                  bool sentSuccessfully = SendNotificationAsync(smtpClient, notification);
      
                  var tuple = new Tuple<NotificationToSend, bool>(notification, sentSuccessfully);
                  tuples.Add(tuple);
              }
          }
      
          return tuples;
      }
      
      private static async Task<bool> SendNotificationAsync(SmtpClient smtpClient, NotificationToSend notification)
      {
          var mailMessage = new MailMessage
          {
              Subject = notification.Subject,
              Body = $"{notification.Text} <br /> This notification was sent automatically",
              IsBodyHtml = true
          };
      
          mailMessage.To.Add(notification.ToEmail);
      
          try
          {
              await smtpClient.SendMailAsync(mailMessage);
              return true;
          }
          catch (Exception e)
          {
              // Here I also plan to log the exception
              return false;
          }
      }
      

      【讨论】:

      • 为什么一开始就处理发送成功的通知?
      • 检查编辑。
      • 现在您还应该确保smtpClientSendNotificationAsync 中处于适当且准备好发送电子邮件的状态,不是吗?
      • 不是真的...此外,如果配置不正确,您会得到布尔值设置为 false 的列表...我认为这就是您想要的,不是吗?
      • 另外,如果传递给mailMessage.To.Add() 的字符串是错误的并且根本不是电子邮件地址怎么办?不会发送通知。
      猜你喜欢
      • 2020-10-07
      • 2015-07-23
      • 1970-01-01
      • 2013-03-21
      • 2013-04-01
      • 2021-09-12
      • 2011-08-10
      • 2011-10-14
      • 1970-01-01
      相关资源
      最近更新 更多