抛出异常:是否封装它们?

时间:2010-06-03 16:30:01

标签: c# .net encapsulation

一旦我阅读了鼓励以下编程范例的MSDN article(它不是100%真实...请参阅编辑):

public class MyClass
{
    public void Method1()
    {
        NewCustomException();
    }

    public void Method2()
    {
        NewCustomException();
    }

    void NewCustomException()
    {
        throw new CustomException("Exception message");
    }
}

你认为这种范式有意义吗?将异常消息存储在static const字段中然后将其传递给异常的构造函数,而不是封装整个异常抛出是不是足够了?

编辑:

  

使用异常构建器方法。它是   对于一个类来说也是常见的   来自不同地方的例外   实现。避免过度   代码,使用创建的辅助方法   例外并将其归还。

我刚注意到(请参阅引文),文章告诉返回例外:

public class MyClass
{
    public void Method1()
    {
        throw NewCustomException();
    }

    public void Method2()
    {
        throw NewCustomException();
    }

    CustomException NewCustomException()
    {
        return new CustomException("Exception message");
    }
}

您如何看待这个?

7 个答案:

答案 0 :(得分:10)

我的理解是,如果除了丢失与异常相关联的堆栈跟踪之外没有其他原因,传递异常实例是一种失礼。调用另一种方法会改变堆栈跟踪,从而使其无效。我建议至少让异常的堆栈跟踪并将其作为参数传递给一些帮助者,如果这是你要去的道路。

答案 1 :(得分:4)

在我的书中,这是一个太过重构的重构。您必须在堆栈跟踪中返回一行,以确切了解问题发生的位置。如果您的自定义异常始终使用相同的消息,请将其放在CustomException类中。如果它在您引用的代码中只是相同,那么是的,将其放在const字段中(您不能static const - 它隐含static)。

答案 2 :(得分:3)

你要做的另一个问题是,有很多地方你甚至无法抛出异常,因为编译器不会允许它。考虑将这两种方法添加到您的班级中:

    public string GetFoo1(bool bar)
    {
        if (bar)
            return "";
        else
            NewCustomException();
    }

    public string GetFoo2(bool bar)
    {
        if (bar)
            return "";
        else
            throw new CustomException("Exception message");
    }

GetFoo1将无法编译,而GetFoo2将会编译。

答案 3 :(得分:2)

我会有一个构建异常的方法,而不是抛出异常的方法。如下面的示例所示。我似乎记得看过推荐这个的Microsoft指南,但我不记得在哪里。

使用此技术,如果您想出于任何原因更改异常类型,则只需在一个位置执行此操作(例如,从.NET升级时从ConfigurationException更改为ConfigurationErrorsException .x到.NET 2.0)。

此外,您还要尊重DRY原则,即使用其消息和异常中包含的任何其他数据构建异常的代码的单个副本。

您显然不会在琐碎的情况下执行此操作(例如,您不会将throw new ArgumentNullException("myParamName")替换为throw BuildArgumentNullException("myParamName")

private static Exception BuildSomeException(... parameters with info to include in the exception ...)
{
    string message = String.Format(...);
    return new SomeException(message, ...);
}

...
throw BuildSomeException(...);

答案 4 :(得分:0)

我没有看到制作简单抛出异常的方法的重点。但是,我确实认为自定义异常具有价值。如果您抛出的所有异常都是自定义异常的子代,则它允许您快速查看抛出的异常是否是您正在考虑的异常,或者您尚未处理的异常。此外,您可以抓住MyBaseException并且它没有抓住Exception那么糟糕。

答案 5 :(得分:0)

如果您不知道计划如何处理异常,那么这样做很方便。你想扔掉它吗?或者也许以后你会在某个地方记录异常然后抛出它?或者传递一些与异常捆绑在一起的参数(即方法名称等)?

在这种情况下,当您想要更改它时,创建一个处理异常情况的单独方法很方便。

我通常不会为此烦恼 - 相反,只需先弄清楚你将如何处理异常(即你要在消息中添加什么字符串信息)。

答案 6 :(得分:0)

我通常更喜欢将异常消息存储为资源。这有几个目的:

  • 如果要求归结为本地化异常消息,那就明白了。
  • 异常消息在开发人员之间往往更加标准化,因为创建一个新的,但只是略有不同的消息是额外的工作。
  • 如果确保消息由标识符引用,并且在抛出时包含带有异常的标识符,则将消息跟踪到抛出它的代码会更容易。

排在后面是它确实需要(仅仅)比硬编码消息更多的努力。