有些帖子询问这两者之间的区别是什么。
(为什么我还要提这个...)

但我的问题是不同的,我称之为“抛出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.}
}

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

throw ex;HandleException调用时,与调用throw具有相同的效果?


#1楼

其他答案完全正确,但我认为这个答案提供了一些额外的答案。

考虑这个例子:

using System;static class Program {static void Main() {try {ThrowTest();} catch (Exception e) {Console.WriteLine("Your stack trace:");Console.WriteLine(e.StackTrace);Console.WriteLine();if (e.InnerException == null) {Console.WriteLine("No inner exception.");} else {Console.WriteLine("Stack trace of your inner exception:");Console.WriteLine(e.InnerException.StackTrace);}}}static void ThrowTest() {decimal a = 1m;decimal b = 0m;try {Mult(a, b);  // line 34Div(a, b);   // line 35Mult(b, a);  // line 36Div(b, a);   // line 37} catch (ArithmeticException arithExc) {Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);//   uncomment EITHER//throw arithExc;//   OR//throw;//   OR//throw new Exception("We handled and wrapped your exception", arithExc);}}static void Mult(decimal x, decimal y) {decimal.Multiply(x, y);}static void Div(decimal x, decimal y) {decimal.Divide(x, y);}
}

如果取消注释throw arithExc; 你的输出是:

Handling a DivideByZeroException.
Your stack trace:at Program.ThrowTest() in c:\somepath\Program.cs:line 44at Program.Main() in c:\somepath\Program.cs:line 9No inner exception.

当然,您丢失了有关异常发生位置的信息。 相反,如果你使用throw; 这就是你得到的:

Handling a DivideByZeroException.
Your stack trace:at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)at System.Decimal.Divide(Decimal d1, Decimal d2)at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58at Program.ThrowTest() in c:\somepath\Program.cs:line 46at Program.Main() in c:\somepath\Program.cs:line 9No inner exception.

这样做要好得多,因为现在你看到是Program.Div方法引起了你的问题。 但是仍然很难看出这个问题是来自try块中的第35行还是第37行。

如果您使用第三个替代方法,包装在外部异常中,则不会丢失任何信息:

Handling a DivideByZeroException.
Your stack trace:at Program.ThrowTest() in c:\somepath\Program.cs:line 48at Program.Main() in c:\somepath\Program.cs:line 9Stack trace of your inner exception:at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)at System.Decimal.Divide(Decimal d1, Decimal d2)at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58at Program.ThrowTest() in c:\somepath\Program.cs:line 35

特别是你可以看到第35行导致问题。 但是,这需要人们搜索InnerException ,并且在简单的情况下使用内部异常感觉有点间接。

在这篇博客文章中,他们通过调用(通过反射) Exception对象上的internal intance方法InternalPreserveStackTrace()来保留行号(try块的行)。 但是使用这样的反射并不好(.NET Framework可能会在某天没有警告的情况下更改其internal成员)。


#2楼

请看这里: http : //blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html

try
{// do some operation that can fail
}
catch (Exception ex)
{// do some local cleanupthrow;
}

它使用Exception保留堆栈信息

这被称为“Rethrow”

如果想抛出新的异常,

throw new ApplicationException("operation failed!");

扔前

try
{// do some operation that can fail
}
catch (Exception ex)
{// do some local cleanupthrow ex;
}

它不会发送带有异常的堆栈信息

这被称为“打破堆栈”

如果想抛出新的异常,

throw new ApplicationException("operation failed!",ex);

#3楼

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. 如果所有第1,第2和第3行都被注释 - 输出 - 内部前

  2. 如果所有第2行和第3行都被注释 - 输出 - 内部ex System.DevideByZeroException:{“试图除以零。”} ---------

  3. 如果所有第1行和第2行都被注释 - 输出 - 内部ex System.Exception:devide by 0 ----

  4. 如果所有第1行和第3行都被注释 - 输出 - 内部ex System.DevideByZeroException:{“试图除以零。”} ---------

如果是throw,则会重置StackTrace;


#4楼

为了给您一个不同的视角,如果您向客户端提供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 callingthrow;                // throw ex;// Display the stack trace from Method4() to Method2() where exception handled}
}

#5楼

让我们理解throw和throw ex之间的区别。 我听说在很多.net采访中都会被问到这个常见问题。

为了概括这两个术语,throw和throw ex都用于了解异常发生的位置。 抛出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 ex替换throw。 如下。

throw ex代码的输出如下。

您可以看到输出中的差异.stone ex忽略所有先前的层次结构,并使用行/方法重置堆栈跟踪,其中写入了throw ex。


#6楼

MSDN代表

抛出异常后,它携带的部分信息就是堆栈跟踪。 堆栈跟踪是方法调用层次结构的列表,该方法调用层次结构以抛出异常的方法开始,并以捕获异常的方法结束。 如果通过在throw语句中指定异常来重新抛出异常,则会在当前方法重新启动堆栈跟踪,并且抛出异常的原始方法与当前方法之间的方法调用列表将丢失。 要保留包含异常的原始堆栈跟踪信息,请使用throw语句而不指定异常。


#7楼

是,有一点不同;

  • throw ex重置堆栈跟踪(因此您的错误似乎来自HandleException
  • throw没有 - 原始罪犯将被保留。

     static void Main(string[] args) { try { Method2(); } catch (Exception ex) { Console.Write(ex.StackTrace.ToString()); Console.ReadKey(); } } private static void Method2() { try { Method1(); } catch (Exception ex) { //throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main) throw ex; } } private static void Method1() { try { throw new Exception("Inside Method1"); } catch (Exception) { throw; } } 

#8楼

不,这将导致异常具有不同的堆栈跟踪。 只使用catch处理程序中没有任何异常对象的throw将使堆栈跟踪保持不变。

您可能希望从HandleException返回一个布尔值,无论是否重新抛出异常。


#9楼

抛出ex时,抛出的异常变为“原始”异常。 所以以前的所有堆栈跟踪都不会存在。

如果你做了抛出,那么异常只是在线上 ,你将获得完整的堆栈跟踪。


#10楼

(我之前发过,@ Marc Gravell纠正了我)

以下是差异的演示:

static void Main(string[] args) {try {ThrowException1(); // line 19} catch (Exception x) {Console.WriteLine("Exception 1:");Console.WriteLine(x.StackTrace);}try {ThrowException2(); // line 25} catch (Exception x) {Console.WriteLine("Exception 2:");Console.WriteLine(x.StackTrace);}
}private static void ThrowException1() {try {DivByZero(); // line 34} catch {throw; // line 36}
}
private static void ThrowException2() {try {DivByZero(); // line 41} catch (Exception ex) {throw ex; // line 43}
}private static void DivByZero() {int x = 0;int y = 1 / x; // line 49
}

这是输出:

Exception 1:at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19Exception 2:at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25

您可以看到在异常1中,堆栈跟踪返回到DivByZero()方法,而在异常2中则不然。

但请注意, ThrowException1()ThrowException2()中显示的行号是throw语句的行号, 而不是DivByZero()调用的行号,这可能是有意义的,因为我认为它是一个位...

在发布模式下输出

例外1:

at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)

例外2:

at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)

它是否仅在调试模式下维护原始stackTrace?

“throw”和“throw ex”之间有区别吗?相关推荐

  1. throw;与throw ex;之间的区别

    很多时候,大家当用到向上抛出异常的时候,常常是throw;和throw ex;随便用,从来都没有留意它们之间的区别.今天我才知道,它们之间是有区别的.原文出自:http://mattgollob.bl ...

  2. throw和throw ex的区别

    之前,在使用异常捕获语句try...catch...throw语句时,一直没太留意几种用法的区别,前几天调试程序时无意中了解到几种使用方法是有区别的,网上一查,还真是,主要是区别在堆栈信息的起始点不同 ...

  3. 程序中try、throw、catch三者之间的关系

    c++程序中,采用一种专门的结构化处理逻辑的异常处理机制. 1.try语句 try语句块的作用是启动异常处理机制,检测try语句块中程序语句执行时可能出现的异常. try语句块总是与catch一同出现 ...

  4. C#使用throw和throw ex的区别

    之前,在使用异常捕获语句try...catch...throw语句时,一直没太留意几种用法的区别,前几天调试程序时无意中了解到几种使用方法是有区别的,网上一查,还真是,主要是区别在堆栈信息的起始点不同 ...

  5. java中separator_java - File.separator和路径中的斜杠之间的区别

    java - File.separator和路径中的斜杠之间的区别 在Java Path-String中使用/和普通的File.separator有什么区别? 与双反斜杠相比,/平台独立似乎不是原因, ...

  6. Java和JavaScript之间的区别

    1.简介 我们将在本文中比较Java语言和JavaScript语言. JavaScript由Netscape开发. 它最初是用于客户端的脚本语言,后来又用作客户端和服务器脚本的语言. Java由Jam ...

  7. Spark源码分析:多种部署方式之间的区别与联系

    作者:过往记忆 从官方的文档我们可以知道, Spark 的部署方式有很多种:local.Standalone.Mesos.YARN-..不同部署方式的后台处理进程是不一样的,但是如果我们从代码的角度来 ...

  8. 我应该如何解释接口和抽象类之间的区别?

    本文翻译自:How should I have explained the difference between an Interface and an Abstract class? In one ...

  9. CountDownLatch,CyclicBarrier,Semaphore的使用方法以及它们之间的区别

    在 JUC 下包含了一些常用的同步工具类,今天就来详细介绍一下,CountDownLatch,CyclicBarrier,Semaphore 的使用方法以及它们之间的区别. 一.CountDownLa ...

最新文章

  1. 前端基础面试题大全-极乐科技(一)-JS部分
  2. golang 切片 slice 去掉重复元素
  3. Oracle迁移至PostgreSQL工具之Ora2Pg
  4. 系统操作日志设计(二)
  5. JavaScript中Map的应用及Map中的bug
  6. poj 2299 (归并排序)
  7. [转载] Java中Runtime的使用
  8. 2020年用于前端开发的顶级JavaScript框架
  9. Failed to initialize storage module: user 的解决方式
  10. excel制图小技巧
  11. PyQt4入门教程(1)_PyQt介绍及准备工作
  12. Python(数据类型思维导图)
  13. 数据结构习题及解析三
  14. 第一章 Activity的生命周期和启动模式
  15. 用表格做一个简单地个人简历
  16. octree与kd-tree对比
  17. datax——全量、增量同步
  18. Mysql数据库分表实现
  19. Keil MDK终于免费了,并且没有代码大小限制~
  20. 外部css样式不生效的原因

热门文章

  1. MFC Map 许多警告
  2. opengl之自动纹理
  3. Android CountDownTimer倒计时器的使用
  4. 设置EditText自动获取焦点并弹出输入法
  5. 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面
  6. python支持中文吗_Python中使用中文
  7. MySQL学习随笔记录
  8. eclipse 的快捷键
  9. zTree中父节点禁用,子节点可以用
  10. qsort函数的用法