有一些帖子问这两者之间已经有什么区别了。(为什么我要提这个…)

但我的问题在某种程度上是不同的,我在另一种错误处理方法中调用了“throw ex”。

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            HandleException(ex);
        }
    }

    private static void HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            throw ex;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            throw ex;
        }
        // and so on.
    }
}

如果在主线中使用try和catch,那么我会使用throw;重新抛出错误。 但是在上面的简单代码中,所有异常都通过HandleException

是否抛出前任;在HandleException内部调用时,与调用throw有相同的效果?


当前回答

为了让您从不同的角度来看待这个问题,如果您向客户端提供API,并且希望为内部库提供详细的堆栈跟踪信息,则使用throw特别有用。通过在这里使用throw,我可以获得File.Delete的System.IO.File库的堆栈跟踪。如果我使用throw ex,那么该信息将不会传递给我的处理程序。

static void Main(string[] args) {            
   Method1();            
}

static void Method1() {
    try {
        Method2();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method1");             
    }
}

static void Method2() {
    try {
        Method3();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method2");
        Console.WriteLine(ex.TargetSite);
        Console.WriteLine(ex.StackTrace);
        Console.WriteLine(ex.GetType().ToString());
    }
}

static void Method3() {
    Method4();
}

static void Method4() {
    try {
        System.IO.File.Delete("");
    } catch (Exception ex) {
        // Displays entire stack trace into the .NET 
        // or custom library to Method2() where exception handled
        // If you want to be able to get the most verbose stack trace
        // into the internals of the library you're calling
        throw;                
        // throw ex;
        // Display the stack trace from Method4() to Method2() where exception handled
    }
}

其他回答

让我们来理解throw和throw ex之间的区别。我听说在很多。net面试中这个常见的问题被问到。

简单介绍一下这两个术语,throw和throw ex都用于理解异常发生的位置。Throw ex重写异常的堆栈跟踪,而不考虑实际抛出的位置。

让我们通过一个例子来理解。

让我们先理解投掷。

static void Main(string[] args) {
    try {
        M1();
    } catch (Exception ex) {
        Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
        Console.WriteLine(ex.StackTrace.ToString());
        Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
        Console.WriteLine(ex.TargetSite.ToString());
    }
    Console.ReadKey();
}

static void M1() {
    try {
        M2();
    } catch (Exception ex) {
        throw;
    };
}

static void M2() {
    throw new DivideByZeroException();
}

上面的输出如下。

显示完整的层次结构和方法名称,实际上已经抛出异常。它是M2 -> M2。还有行号

其次……让我们理解throw ex。只需在M2方法catch块中将throw替换为throw ex。如下。

throw ex代码的输出如下。

你可以在输出中看到差异。Throw ex只是忽略了之前的所有层次结构,并使用写入Throw ex的line/method重置堆栈跟踪。

为了让您从不同的角度来看待这个问题,如果您向客户端提供API,并且希望为内部库提供详细的堆栈跟踪信息,则使用throw特别有用。通过在这里使用throw,我可以获得File.Delete的System.IO.File库的堆栈跟踪。如果我使用throw ex,那么该信息将不会传递给我的处理程序。

static void Main(string[] args) {            
   Method1();            
}

static void Method1() {
    try {
        Method2();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method1");             
    }
}

static void Method2() {
    try {
        Method3();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method2");
        Console.WriteLine(ex.TargetSite);
        Console.WriteLine(ex.StackTrace);
        Console.WriteLine(ex.GetType().ToString());
    }
}

static void Method3() {
    Method4();
}

static void Method4() {
    try {
        System.IO.File.Delete("");
    } catch (Exception ex) {
        // Displays entire stack trace into the .NET 
        // or custom library to Method2() where exception handled
        // If you want to be able to get the most verbose stack trace
        // into the internals of the library you're calling
        throw;                
        // throw ex;
        // Display the stack trace from Method4() to Method2() where exception handled
    }
}
int a = 0;
try {
    int x = 4;
    int y ;
    try {
        y = x / a;
    } catch (Exception e) {
        Console.WriteLine("inner ex");
        //throw;   // Line 1
        //throw e;   // Line 2
        //throw new Exception("devide by 0");  // Line 3
    }
} catch (Exception ex) {
    Console.WriteLine(ex);
    throw ex;
}

如果所有第1、2和3行都注释了- 输出-内ex 如果所有第2行和第3行都注释了- 输出-内ex 系统。DevideByZeroException:{"试图除零。"}--------- 如果所有第1行和第2行都注释了- 输出-内ex 系统。例外:除0 ---- 如果所有第1行和第3行都注释了- 输出-内ex 系统。DevideByZeroException:{"试图除零。"}---------

和StackTrace将重置的情况下抛出ex;

为了扩展Lucero的回答,下面介绍如何在不丢失原始堆栈跟踪的情况下实现原始代码的意图。

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            if (!HandleException(ex)) throw;
        }
    }

    /// <returns>
    ///   true if the exception has been handled;
    ///   false if exception should be passed along
    /// </returns>
    private static bool HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return true;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            return false;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            return false;
        }
        // and so on.
    }
}

最好使用throw而不是throw ex。

Throw ex重置原始堆栈跟踪,无法找到之前的堆栈跟踪。

如果使用throw,我们将得到一个完整的堆栈跟踪。