在C#中捕获异常时应返回什么?

3

这可能是一个相当简单的问题,但try-catch块的返回类型最佳实践是什么?目前,我正在执行以下操作:

 public List<SomeAttribute> FindAttributes(int id)
   {
       try
       {
            //Some query and some logic
       }
       catch (Exception ex)
       {
           Logger.Error(ex);
           return new List<SomeAttribute>();
       }
   }

这有什么特别糟糕的吗?异常将被记录,并且该方法将返回一个空列表-调用函数可以处理。返回null更好吗?如果是,为什么?


10
如果没有合理的返回值,你可能需要考虑让调用者处理错误。 - chris
1
问题是:为什么要捕获异常,你可以将其继续抛出... - Willem Van Onsem
5
这是一个基于观点的问题,但它真的取决于你在代码中的具体操作。也许你可以恢复数据并返回请求的实际数据,或者你想返回空值作为错误指示,或者你想重新抛出异常。根据你的问题很难给出明确的答案。 - JNYRanger
3
如何区分“无结果”和“发生错误”?如果调用者继续使用您的空列表,会发生什么? - CodeCaster
好的,FindAttributes()方法可能会在很多地方被调用,而且最常见的错误与服务器超时或达到某些配额限制有关,所以我希望在实际执行查询的方法中捕获它,而不是在调用该方法的所有其他地方。 - RamblerToning
3
如果你回答不了那个问题,最好干脆不要捕获异常。 - SLaks
1个回答

6
一般来说,人们考虑三种处理部分函数(仅在输入域的子集上有效的函数)的策略:全面防御性名义上

全面策略

这意味着您始终返回一个答案。在这种情况下,您可以考虑返回一个null-指针,例如在String.IndexOf的情况下,返回-1优点:
  • It is sometimes easier for a the caller not to think about potential errors. Sometimes the return value can be useful. For instance if you want to cut off a the first part of a string up (and including the first comma), you can code this as:

    string foo = "Foo,Bar"
    string foocut = foo.SubString(foo.IndexOf(',')+1); //Bar, in case no comma, it returns the entire string
    

    Thus resulting in more compact code. But on the other hand it's sometimes hard to determine what the best return value is.

缺点:

  • 需要进行工程化来确定“最佳”返回值。有许多选项,每个选项只对部分调用者有益。
  • 有时无法区分有效输出和在出现问题时(默认)输出之间的差异。

防御式编程

在这里,您会抛出异常(或不捕获异常)。由特定于领域的调用者决定为什么抛出了异常并进行准确处理。通常情况下,Util方法对系统没有太多了解,因此不知道异常发生的原因。

优点:

  • 调用者可以使用最好的知识来处理异常(因此具有某种“责任链”)。这可以导致更好的错误处理(向用户提供有用的消息)。不是“在SQL查询中发生错误...”,而是“用户名已存在。”

缺点:

  • 错误处理有时很困难。特别是在C#中,人们不需要注释哪些异常可能被方法抛出。覆盖所有类型的异常并不容易。未捕获的异常可能会返回到顶部的Main调用,从而使应用程序崩溃。对于某些应用程序,例如Web服务器,这并不总是一个选项。

名义式编程

在这里,您会记录方法并提供前提条件:在文档中,您指定了使用该方法的正确方式。这并不总是可能的,因为有时方法成功的事实取决于外部因素(服务器的可用性、操作系统的类型等)。这些因素不一定由程序员控制。

优点:

  • 导致方法得到很好记录(有时是严格定义的)。
  • 实现方法(callee)更容易,因为它可以假设一切都会正常工作。

缺点:

  • 不总是可能的(有时结果确实取决于人们无法控制的因素)。
  • 编写调用者更困难,因为它有一个合同,即只调用具有正确参数的方法。
  • 还很难记录所有条件以及验证每个调用是否满足它们。有时使用代码合同来处理验证(部分)自动化。

大多数程序不仅使用一种策略,而是混合使用它们:例如,有些异常是完全处理的,其他异常是名义上的,而其他模块遵循防御性策略,而另一个使用名义式编程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接