Is General Exception handling not so bad in this case? [closed]

限于喜欢 提交于 2019-12-11 07:47:03

问题


In the code below I try to send a set of notifications and I want to know if a notification was sent successfully (to put it in a database later so never send it again).

Is it bad I'm catching Exception here? I really don't care about the reason a notification wasn't sent.

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;
}

回答1:


You should never use catch(Exception e), you should only catch exceptions that you know can be thrown. And with the SmtpClient the MSDN documentation says that one of the following four exceptions can be thrown:

  • ArgumentNullException
  • InvalidOperationException
  • ObjectDisposedException
  • SmtpException

So you should do it like this:

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
}

The reason for this is much better logging, if you know the exception that was thrown the log could display something like 'ArgumentNullException was thrown, *insert a possible explanation as to why*'

Or if you want to handle all exceptions the same way:

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:


Depends what behavior you want to achieve. Blanket catch like this will make program "limp" even if someone introduces a blunt error like null reference inside try...catch. Usually this is not desired and it's better to fail fast.

If you want program to carry on only after 'expected' SMTP infrastructural error then catch only specific types of exceptions (e.g. SmtpException or whatever can be thrown by SendMailAsync) and otherwise let the exception to bubble up.




回答3:


What I'd go for:

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;
    }
}


来源:https://stackoverflow.com/questions/57588098/is-general-exception-handling-not-so-bad-in-this-case

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!