异常抛出:是否封装它们?
有一次我阅读了 MSDN 文章鼓励以下编程范式(它不是 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");
}
}
您对此有何看法?
Once I read an MSDN article that encouraged the following programming paradigm (its not 100% true... see edit):
public class MyClass
{
public void Method1()
{
NewCustomException();
}
public void Method2()
{
NewCustomException();
}
void NewCustomException()
{
throw new CustomException("Exception message");
}
}
Do you think this paradigm makes sense? Wouldn't it be enough to store the exception message in a static const
field and then pass it to the exception's constructor, instead of encapsulating the whole exception throw?
EDIT:
Use exception builder methods. It is
common for a class to throw the same
exception from different places in its
implementation. To avoid excessive
code, use helper methods that create
the exception and return it.
I just noticed (see citation), that the article tells to return an exception:
public class MyClass
{
public void Method1()
{
throw NewCustomException();
}
public void Method2()
{
throw NewCustomException();
}
CustomException NewCustomException()
{
return new CustomException("Exception message");
}
}
What do you think about this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我的理解是,如果没有其他原因,除了丢失与异常相关的堆栈跟踪之外,传递异常实例是一种失礼行为。调用另一个方法会改变堆栈跟踪,从而使其变得毫无用处。我建议至少从异常中获取堆栈跟踪并将其作为参数传递给某个助手(如果这是您要走的路)。
My understanding is that passing an exception instance around is a faux pas if for no other reason than you lose the stack trace associated with the exception. Calling another method would change the stack trace and thereby make it effectively useless. I'd recommend at a minimum getting the stack trace off the exception and passing it as an argument to some helper if that's the road you're going to go down.
在我的书中,这个重构太过分了。您必须返回堆栈跟踪中的一行才能准确查看问题发生的位置。如果您的自定义异常始终使用相同的消息,请将其放入
CustomException
类中。如果它仅在您引用的代码中相同,那么是的,将其放入const
字段中(您不能使用static const
- 它隐式静态
)。That's a refactor too far in my book. You have to go back up a line in the stack trace to see exactly where the problem occured. If your custom exception is always using the same message, put it in the
CustomException
class. If it's only the same within the code you've quoted, then yes, put it in aconst
field (you can't havestatic const
- it's implicitlystatic
).这样做的另一个问题是,在很多地方你甚至无法抛出异常,因为编译器不允许它。考虑将这两个方法添加到您的类中:
GetFoo1 不会编译,而 GetFoo2 可以。
Another problem you get doing that is that there will be lots of places where you wont even be able to throw an exception because the compiler wont allow it. Consider these two methods added to your class:
GetFoo1 will not compile while GetFoo2 will.
我想要一种构建异常的方法,而不是抛出异常的方法。如下面的示例所示。我似乎记得看到过推荐这样做的微软指南,但我不记得在哪里了。
使用这种技术,如果您出于任何原因想要更改异常类型,则只需在一个地方执行此操作(例如,在升级时从
ConfigurationException
更改为ConfigurationErrorsException
.NET 1.x 到 .NET 2.0)。此外,您还可以通过使用构建异常及其消息和异常中包含的任何其他数据的代码的单个副本来尊重 DRY 原则。
您显然不会在微不足道的情况下执行此操作(例如,您不会将 throw new ArgumentNullException("myParamName") 替换为
throw BuildArgumentNullException("myParamName")
)I would have a method that builds an Exception, rather than one that throws it. As in the sample below. I seem to remember seeing a Microsoft guideline that recommended this, but I can't remember where.
With this technique, if you want to change the exception type for any reason, you only need to do so in one place (e.g. a change from
ConfigurationException
toConfigurationErrorsException
when upgrading from .NET 1.x to .NET 2.0).Also you respect the DRY principle by having a single copy of the code that builds the exception with its message and any other data included in the exception.
You obviously wouldn't do this in trivial cases (e.g. you wouldn't replace
throw new ArgumentNullException("myParamName")
bythrow BuildArgumentNullException("myParamName")
)我不认为创建一个简单地抛出异常的方法有什么意义。但是,我确实认为抛出自定义异常是有价值的。如果您抛出的所有异常都是自定义异常的子异常,那么您可以快速查看抛出的异常是您正在考虑的异常还是您尚未处理的异常。另外,您还可以捕获
MyBaseException
,而且它并不像捕获Exception
那么糟糕。I don't see the point of making a method that simply throws an exception. But, I do think trowing custom exceptions has value. If all of the exceptions you throw are children of a custom exception, it allows you to quickly see if the thrown exception is one you are accounting for or something you have not handled yet. Also, you can then catch
MyBaseException
and it is not as bad as catchingException
.如果您不知道计划如何准确地处理异常,那么这样做会很方便。你想直接扔掉它吗?或者也许稍后您将在某个地方记录异常然后抛出它?或者也许传递一些与异常捆绑在一起的参数(即方法名称等)?
在这种情况下,当您想要更改异常情况时,创建一个单独的方法来处理异常情况会很方便。
我通常不会为此烦恼 - 相反,只需预先弄清楚您将如何处理异常(即您将在消息中放入哪些字符串信息)。
It is handy to do this if you don't know how you plan to handle exceptions, exactly. Do you want to just throw it? Or perhaps later you are going to log the exception somewhere then throw it? Or maybe pass some arguments (i.e. method name, etc.) that get bundled in with the exception?
In this case, creating a separate method that handles the exception situation is convenient when you want to change it.
I don't usually bother with this - instead, just figure out upfront how you are going to handle exceptions (i.e. what string information you are going to putin the message).
我通常更喜欢将异常消息存储为资源。这有几个目的:
缺点是它确实需要比硬编码消息稍微多一点的工作。
I generally prefer to store exception messages as resources. That serves several purposes:
Downside is it does require (just) slightly more effort up front than hard-coding the messages.