【问题标题】:Catching base but not sub exceptions捕捉基础但不捕捉子异常
【发布时间】:2015-03-13 10:41:59
【问题描述】:

我正在编写一个 HttpHandler,作为我内部设计的一部分,我抛出不同的异常并在顶层捕获它们以确定将请求设置为什么状态代码。

即 ArgumentException 触发错误请求
AuthenticationException 触发未经授权的
OracleException 触发 InternalServerError
等等

我发现的问题是我使用 InvalidOperationException 来触发 NotFound,但是我的代码中的一个错误使我意识到,当然,某些系统异常继承自这些基本系统异常,这会导致意外响应。

即我发现ObjectDisposedException继承自InvalidOperationException,也就是说响应返回的是404而不是500。

有没有办法只捕获基本异常?

我找到了this thread,这表明我可以做一个过滤器并重新抛出,但这似乎很老套。

我最好创建自己的异常类型来省去所有这些麻烦吗?

【问题讨论】:

  • 是的,你当然应该为这个特定的用例推出你自己的例外,而不是使用InvalidOperationException
  • 绝对不要提出InvalidOperationException 不是为了它的意思。同样适用于任何其他例外。制作您自己的例外,并以Exception 为基础。只需确保在抛出自己的异常时将原始异常作为内部异常传递,以维护调用堆栈。我不知道你为什么投了反对票,这是一个合法且非常常见的错误。
  • @mattm @bokibeg 谢谢你,我可能应该阅读文档,了解 .NET 对 InvalidOperationException 的定义。我将定义自己的异常并将所有捕获的异常包装在其中。
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。

标签: c# exception


【解决方案1】:

如果您只想将 HTTP 结果代码(可能还有错误消息行)传递给客户端,那么我建议您创建一个 single 自定义异常:

public class MyCustomException : Exception { // Or maybe InvalidOperationException
    public int StatusCode {get;set;}
    public string Status {get;set;}
}

等等

【讨论】:

  • 这个主意不错,我总是忘记你可以为异常添加更多属性!但是,我认为我更喜欢拥有一组自定义异常。虽然它增加了一些代码开销,但 IMO 的代码看起来更简洁(throw BadRequestExeption("msg") 而不是throw HttpErrorException(400, "msg")
  • 您应该尽量减少您创建的自定义异常类的数量。特别是在这种情况下,它们都是相同的。您可以创建一组工厂方法来创建特定类型,此外,您谈论的是两个参数而不是一个。
  • 在我的脑海中,我总是认为异常是一头独立的野兽,忘记了它们只是类。我更喜欢单独的命名类,因为它更容易从(而不是状态代码)获得含义,但是工厂函数的想法很棒,因为它允许一个带有混淆命名调用的异常类。我已经实现了。如果您可以将该部分添加到您的答案中,我会将其标记为已接受。
【解决方案2】:

据我所知,没有办法捕获异常但不能捕获继承的异常。问题是您正在考虑基本异常比继承异常更具体,这与它们的工作方式相反(继承异常应该是其父异常的更具体的子集,所以从概念上讲,如果你可以处理您应该能够处理继承异常的父级)。

您的选择基本上是:

  1. 创建您自己的异常类型并仅捕获它。如果您的异常属于InvalidOperationException 的定义,那么您可以继承它。然后你就可以专门抓到你的了。
  2. 如果不是您想要的,请抓住、检查并重新投掷。我通常会尽量避免使用这种技术,但如果异常类型过于通用,有时会需要这种技术。例如

    catch (InvalidOperationException ex) { 
       if (ex.GetType() != typeof(InvalidOperationException)) throw;
       /* Do stuff */
    }
    

【讨论】:

    【解决方案3】:

    不可能只捕获基本异常。

    在这种情况下最好创建自定义异常,而不是使用系统的异常类型。

    public class HttpErrorException : Exception
    {
        public HttpStatusCode StatusCode { get; private set; }
        public HttpErrorException(HttpStatusCode code, string message)
            : base(message)
        {
            this.StatusCode = code;
        }
    }
    
    throw new HttpErrorException(400, "You sent a bad request!");
    

    如果最初的目的是混淆 HTTP 状态码,而是使用它们的文本名称,则可以创建工厂方法。

    public class HttpErrorException : Exception
    {
        public HttpStatusCode StatusCode { get; private set; }
    
        private HttpErrorException(HttpStatusCode code, string message)
            : base(message)
        {
            this.StatusCode = code;
        }
    
        public static HttpErrorException BadRequest(string message)
        {
            return new HttpErrorException(400, message);
        }
    
        public static HttpErrorException InternalServerError(string message)
        {
            return new HttpErrorException(500, message);
        }
        // etc
    }
    
    throw HttpErrorException.BadRequest("You made a bad request!");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      • 2020-04-20
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      相关资源
      最近更新 更多