C# try/catch/throw和try/catch(e)/throw e之间的区别

C# try/catch/throw和try/catch(e)/throw e之间的区别,c#,exception-handling,C#,Exception Handling,两者的区别是什么 try { } catch { throw; } 及 ? 什么时候应该使用一个或另一个?第一个保留堆栈跟踪,而第二个重置堆栈跟踪。这意味着,如果使用第二种方法,异常的堆栈跟踪将始终从该方法开始,并且您将丢失原始异常跟踪,这对于阅读异常日志的人来说可能是灾难性的,因为他永远不会找到异常的原始原因 当您希望向堆栈跟踪添加其他信息时,第二种方法可能很有用,但它的使用方式如下: try { // do something } catch (Exception ex) {

两者的区别是什么

try { }
catch
{ throw; }

?


什么时候应该使用一个或另一个?

第一个保留堆栈跟踪,而第二个重置堆栈跟踪。这意味着,如果使用第二种方法,异常的堆栈跟踪将始终从该方法开始,并且您将丢失原始异常跟踪,这对于阅读异常日志的人来说可能是灾难性的,因为他永远不会找到异常的原始原因

当您希望向堆栈跟踪添加其他信息时,第二种方法可能很有用,但它的使用方式如下:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}
这里有一个讨论差异的论坛。

您应该使用

try { }
catch(Exception e)
{ throw }
如果您想在重新抛出异常之前处理异常(例如日志记录)。孤注一掷保留堆栈跟踪。

结构

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }
类似的是,两者都将捕获
try
块中抛出的每个异常(并且,除非您只是使用它来记录异常,否则应该避免)。现在看看这些:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}
第一个try-catch块和第二个try-catch块完全相同,它们只是重新显示当前异常,该异常将保留其“源”和堆栈跟踪

第三个try-catch块是不同的。当它抛出异常时,它将更改源和堆栈跟踪,以便显示异常是从包含try-catch块的方法上的
throw e
这一行抛出的

你应该用哪一种?这取决于每种情况

假设您有一个
Person
类和一个
.Save()
方法,该方法将把它持久化到数据库中。假设应用程序在某处执行
Person.Save()
方法。如果数据库拒绝保存此人,则
.save()
将引发异常。在这种情况下,您应该使用
throw
还是
throw e
?那要看情况了

我更喜欢做的是:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}
这应该将DBException作为正在抛出的较新异常的“内部异常”。因此,当您检查此InvalidPersonException时,堆栈跟踪将包含返回到Save方法的信息(这可能足以解决问题),但如果需要,您仍然可以访问原始异常

最后一句话,当您预期出现异常时,您应该真正捕捉到一个特定的异常,而不是一般的
异常
,也就是说,如果您预期出现InvalidPersonException,您应该选择:

try { ... }
catch (InvalidPersonException e) { ... }


祝你好运

无参数catch和
catch(异常e)
之间的区别在于您获得了对异常的引用。从FrameworkVersion2开始,非托管异常被包装在托管异常中,因此无参数异常对任何事情都不再有用

throw之间的差异
抛出e,第一个用于重新抛出异常,第二个用于抛出新创建的异常。如果使用第二个异常来重新抛出异常,它会将其视为新异常,并替换最初抛出异常的所有堆栈信息

所以,你不应该使用问题中的任何一个选项。您不应该使用无参数catch,而应该使用
throw
以重新显示异常

此外,在大多数情况下,您应该为所有异常使用比基类更具体的异常类。您应该只捕获预期的异常

try {
   ...
} catch (IOException e) {
   ...
   throw;
}
如果要在重新引发异常时添加任何信息,请创建一个新异常,将原始异常作为内部异常,以保留所有信息:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}

知道这些真是太好了!那么为什么要使用第二个呢?只使用第一个是否更好?第二个在需要检查特定异常时有用,比如OutOfRangeExtExcor——或者需要记录消息等。第一个似乎是通配符异常处理程序,类似于C++中的{{}} catch(…){}。戴维只适用于catch(Exchange E)部分。这与throw
vs
throw e
是分开的。如果我把这里的“throw”替换为“throw e”,会发生什么?
try {
   ...
} catch (IOException e) {
   ...
   throw;
}
try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}