捕获异常、添加数据并重新抛出

32

我有以下代码:

try
{
   OnInitialize();
}
catch (PageObjectLifecycleException exception)
{
   exception.OldLifecycleState = CurrentLifecycleState;
   exception.RequestedLifecycleState = LifecycleState.Initialized;
   throw exception;
}

我捕获了一个异常,向其中添加了一些数据,并将其重新抛出。Resharper正确地警告我可能有意进行重新抛出,并建议将其更改为:

throw;

但我在想:这样会正确地重新抛出修改过的异常还是未经修改的原始异常?

编辑:针对“试一试并查看”评论的回应:我是C++新手,现在学习C#。在C++中,你经常会在这种边缘情况下遇到未定义的行为,我想知道我想要的是否真的是官方如何工作的。


7
试一试,看看会发生什么? - Justin Niessner
它将重新抛出引用指向的任何内容 - 在您的情况下是修改后的“异常”。 - james lewis
4个回答

60

您可以将额外的信息添加到数据中,并使用 throw 重新抛出异常,以便保持其原始形式和调用堆栈。

try
{
   ...
}
catch (PageObjectLifecycleException exception)
{
   exception.Data.Add("additional data", "the additional data");
   throw;
}

6
这真的应该成为被接受的答案,这就是Data的作用。只要防止关键字冲突,并牢记字典中包含的任何信息都会1)沿调用链传播和2)可以在途中修改,那么这是一个很好的方法来添加有用的信息以便于调试。 - s.m.
1
防止键冲突异常的一种方法是使用exception.Data["additional data"] = "the additional data"。是的,现有数据将被覆盖,但至少不会抛出新的ArgumentException,这会隐藏原始异常。 - Justin J Stark
@JustinJStark 不错的观点,你不需要任何新的异常。但是由于它是一个集合,您必须小心不存在的项异常。您可以使用 if 检查是否已经存在现有的项。在这里,您可以详细说明错误处理,而不是关键路径。 - Menelaos Vergis
我选择了这个,但系统告诉我需要引用 Microsoft.CSharp.dll。有人知道为什么吗?只是好奇... - Eric

29

虽然答案已经被选定,但我这里有一些更多关于这个主题的信息。

try {
    // code
}
catch(Exception e) {
    throw e;
}

上面的代码在编译成IL之后,将生成一个对throw的调用,该调用将处理的异常作为参数传递。如您所知,您可以从代码中的任何位置调用throw来引发异常。

try {
    // code
}
catch(Exception e) {
    throw;
}
上述代码编译成 IL 后将产生对 rethrow 方法的调用。这与 throw 不同,因为 rethrow 用于表示处理异常的块由于某种原因决定不处理它,因此责任应该被提供给更高级别的 catch 块(上一个块)。
rethrow 方法保留当前调用堆栈跟踪,以便可以追踪异常的来源。但是,throw 方法启动一个新的调用堆栈跟踪。我认为,一旦您理解了两种方法的使用方式,就会明白这是有道理的。
在我的经验中,当您想出现异常时(例如对象验证失败)时,使用 throw exception;,而在执行某些日志记录后(即在将异常处理责任传递给更高级别之前仍然可以访问对象中有用信息的情况下),您会在 catch 语句中使用 throw;。
在您的示例中,如果您需要向异常添加更多信息,则应创建一个全新的异常并引发它。 因此,在 "exception" 是包含额外信息和最初抛出的异常的新异常的情况下,您将使用 throw exception; 方法。
希望这有所帮助!
詹姆斯

11

这将抛出已修改异常的引用。

但是,我不确定这是否是良好的编程风格。考虑创建一个新异常并将PageObjectLifecycleException作为其内部异常添加。这样处理代码就可以确定它是否具有正确的附加信息。


我也是,这是一个真正的bug隐藏者。例如,外部catch块会践踏从更深层次传回的数据。 - Tony Hopkinson
代码示例已经简化。不会覆盖任何现有数据,只会提供一些缺失的附加数据。 - Sebastian Negraszus
1
@TonyHopkinson Exception.Data听起来就像是为这个目的而设计的(在这里)。 - drzaus

2

当前的异常被重新抛出,虽然我不确定你的模式是否是一个非常好的和可维护的模式。


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