构建异常消息的最佳做法是什么?

时间:2017-08-24 09:33:54

标签: c# .net exception design-patterns

当您的程序出现问题时,您可以在代码中抛出一个异常,其中包含描述问题的消息。典型的例子:

throw new Exception("Houston we have a problem");

将硬编码字符串传递给异常构造函数是一种好习惯吗?也许我应该在一个地方保存所有异常消息。请告诉我解决异常消息结构问题的最佳实践。

2 个答案:

答案 0 :(得分:2)

  

将硬编码字符串传递给异常构造函数是一种好习惯吗?

是和否。

没有这个代码:

throw new Exception("Houston we have a problem");

对于来电者来说要困难得多。这是因为异常意味着只能通过消息文本来识别;因此,调用者希望从代码中捕获异常(例如,为了不崩溃但如果可能继续运行)必须进行字符串比较以找出问题所在。

e.g。

try
{
     someService.DoSomething(sessionId)
}
catch(Exception ex)
{
  if (ex.Message.Contains("Houston"))
  {
      //this indicates that someService couldn't connect to the database
  }
  else if(ex.Message.Contains("is on fire"))
  {
      //someService detected that the network is exploded
  }
  else{
  //we can only handle the two previous cases, all else is passed on}
  throw;       
}

正如你所看到的,这会变得很乱,如果有人改变文字......

现在代码:

throw new SomethingSpecificWentWrongException(sessionId);

SomethingSpecificWentWrongException可能如下所示:

public class SomethingSpecificWentWrongException: Exception
{
   public int SessionId  {get;protected set;}
   public SomethingSpecificWentWrongException(int sessionId): 
     base($"Something specific went horribly wrong with session {sessionId}")
   {
     SessionId=sessionId;
   }
}

可以很容易地由来电者处理:

try
{
     someService.DoSomething(sessionId)
}
catch(SomethingSpecificWentWrongException ex)
{
    //do whatever it is you do to recover from this
}
catch(SomethingElseSpecificWentWrongException wex)
{
    //recover from this
}
else
{
 throw;
}

你会注意到这里有一个硬编码的字符串,但是它由自定义异常类本身拥有,而不是由决定抛出异常的代码所拥有;这会产生很大的不同,因为这意味着您可以保证无论在何处使用此异常,消息都是可预测的(在日志记录方面等)。 因此,它不仅更易于推理,而且比投掷代码提供的硬编码字符串更易于维护。

答案 1 :(得分:1)

正如Tim在评论中提到的,如果向用户显示消息,本地化可能会成为一个问题。

我对这个主题的看法是什么,我真正想建议的是以下内容。

尝试将其设为通用

Makea一个持有异常的常量类带有有意义的常量名称的消息,如下所示:

public static const String IN_VARIABLE_MISSING = "An expected value is missing. Please try again";

这将使您能够在需要的地方实际重用异常。 (你只需要在一个地方编辑它并在任何地方更新它)你可以构建一个处理本地化的包装器。但是这个话题有很多选择,我不会详细说明。

所以你可以抛出这样的异常:

throw new Exception(IN_VARIABLE_MISSING);

如果这是将用于商业用途的软件,我还建议编写一个扩展标准异常的自己的异常。

为什么?

您可以创建一个例外信息来接收您的信息和一个号码,并为您自动构建一个唯一的密钥:

IN-MODULE-NUMBER-IDENTIFICATION

你知道哪里可以派上用场吗?在本地化和更快地发现它发生的地方以及为什么发生这种情况时都是如此。

您可以修改它以在内部错误的开头写入INVA表示验证错误。然后是它发生的类/项目,然后是数字或任何你想要的。

此系统还允许您根据用户使用的语言环境为该键使用另一个字符串。

TL; DR 让它可重复使用!