这样做更好吗:

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw;
}

或:

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw ex;
}

他们做同样的事情吗?一个比另一个好吗?


当前回答

视情况而定。在调试构建中,我希望尽可能少地查看原始堆栈跟踪。在这种情况下,“throw;”符合要求。

然而,在发布版本中,(a)我想记录包含原始堆栈跟踪的错误,一旦完成,(b)重新设计错误处理以使用户更有意义。这里“抛出异常”是有意义的。重新抛出错误确实会丢弃原始的堆栈跟踪,但非开发人员从查看堆栈跟踪信息中得不到任何信息,因此可以重新抛出错误。

        void TrySuspectMethod()
        {
            try
            {
                SuspectMethod();
            }
#if DEBUG
            catch
            {
                //Don't log error, let developer see
                //original stack trace easily
                throw;
#else
            catch (Exception ex)
            {
                //Log error for developers and then
                //throw a error with a user-oriented message
                throw new Exception(String.Format
                    ("Dear user, sorry but: {0}", ex.Message));
#endif
            }
        }

问题的措辞,让"Throw:"和。“Throw ex;”让它有点转移注意力。真正的选择是在“Throw;”和“Throw Exception”之间,其中“Throw ex;”是“Throw Exception”的一个不太可能的特例。

其他回答

您应该始终使用以下语法来重新抛出异常。否则你将停止堆栈跟踪:

throw;

如果打印由throw ex产生的跟踪,您将看到它结束于该语句,而不是异常的真正来源。

基本上,使用抛掷前女友应该被视为刑事犯罪。


如果需要重新抛出来自其他地方(AggregateException, TargetInvocationException)或另一个线程的异常,也不应该直接重新抛出。而是使用ExceptionDispatchInfo保存所有必要的信息。

try
{
    methodInfo.Invoke(...);
}
catch (System.Reflection.TargetInvocationException e)
{
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
    throw; // just to inform the compiler that the flow never leaves the block
}

如果抛出一个没有变量的异常(第一个例子),堆栈跟踪将包括抛出异常的原始方法。

在第二个示例中,堆栈跟踪将被更改以反映当前方法。

例子:

static string ReadAFile(string fileName) {
    string result = string.Empty;
    try {
        result = File.ReadAllLines(fileName);
    } catch(Exception ex) {
        throw;    // This will show ReadAllLines in the stack trace
        throw ex; // This will show ReadAFile in the stack trace
    }

你应该总是使用"throw;"来重新抛出。net中的异常,

请参考博客文章《甩和甩前男友》。

基本上,MSIL (CIL)有两个指令——“throw”和“rethrow”,c#的“throw ex;”被编译成MSIL的“throw”和c#的“throw;”-进入MSIL“重扔”!基本上,我可以看到为什么“throw ex”覆盖堆栈跟踪的原因。

视情况而定。在调试构建中,我希望尽可能少地查看原始堆栈跟踪。在这种情况下,“throw;”符合要求。

然而,在发布版本中,(a)我想记录包含原始堆栈跟踪的错误,一旦完成,(b)重新设计错误处理以使用户更有意义。这里“抛出异常”是有意义的。重新抛出错误确实会丢弃原始的堆栈跟踪,但非开发人员从查看堆栈跟踪信息中得不到任何信息,因此可以重新抛出错误。

        void TrySuspectMethod()
        {
            try
            {
                SuspectMethod();
            }
#if DEBUG
            catch
            {
                //Don't log error, let developer see
                //original stack trace easily
                throw;
#else
            catch (Exception ex)
            {
                //Log error for developers and then
                //throw a error with a user-oriented message
                throw new Exception(String.Format
                    ("Dear user, sorry but: {0}", ex.Message));
#endif
            }
        }

问题的措辞,让"Throw:"和。“Throw ex;”让它有点转移注意力。真正的选择是在“Throw;”和“Throw Exception”之间,其中“Throw ex;”是“Throw Exception”的一个不太可能的特例。

第一个保存异常的原始堆栈跟踪,第二个用当前位置替换它。

因此,到目前为止,第一个是更好的。