difference between throw and throw new Exception()
两者有什么区别
1 2 | try { ... } catch{ throw } |
和
1 2 |
不管第二个显示什么信息?
< BR>
不写< BR>
在某些情况下,您可能希望将所有异常包装在一个自定义异常对象中,这样您就可以提供有关在引发异常时代码在做什么的附加信息。
为此,定义一个继承
第一个保留原始stacktrace:
1 2 3 4 5 6 | try { ... } catch { // Do something. throw; } |
第二个允许您更改异常的类型和/或消息和其他数据:
1 2 3 4 |
还有第三种方法可以通过内部异常:
1 2 3 4 |
我建议使用:
- 第一种方法是在错误情况下进行一些清理,而不破坏信息或添加有关错误的信息。
- 第三个,如果您想添加关于错误的更多信息。
- 第二个,如果你想隐藏信息(对不受信任的用户)。
还有一点我没看到有人说:
如果您在catch块中没有做任何事情,尝试…catch是没有意义的。我一直看到这个:
1 2 3 4 5 6 7 8 | try { //Code here } catch { throw; } |
或更糟:
1 2 3 4 5 6 7 8 | try { //Code here } catch(Exception ex) { throw ex; } |
最糟糕的是:
1 2 3 4 5 6 7 8 |
抛出一个新的异常将清除当前堆栈跟踪。
1 2 3 4 |
通常情况下,您会单独使用
Blackwasp有一篇很好的文章,题为《在C中抛出异常》。
在不带任何参数的情况下使用
引发;重新引发原始异常并保留异常类型。
throw new exception();重新引发原始异常类型并重置异常堆栈跟踪
throw ex;重置异常堆栈跟踪并重置异常类型
throw或throw-ex都用于抛出或重新引发异常,当您只需记录错误信息,不想将任何信息发送回调用方时,只需将错误记录在catch中并离开。但是,如果您想向使用throw或throw-ex的调用者发送一些关于异常的有意义的信息,那么throw和throw-ex的区别在于throw保留了堆栈跟踪和其他信息,而throw-ex创建了一个新的异常对象,因此原始的堆栈跟踪将丢失。所以当我们应该使用throw和throw e时,仍然有一些情况下您可能希望重新引发异常,比如重置调用堆栈信息。例如,如果该方法位于库中,并且您希望从调用代码中隐藏库的详细信息,则不一定希望调用堆栈包含库中私有方法的信息。在这种情况下,您可以捕获库的公共方法中的异常,然后重新执行这些异常,以便调用堆栈从这些公共方法开始。
最重要的区别是第二个表达式删除异常类型。异常类型在捕获异常中起着至关重要的作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public void MyMethod () { // both can throw IOException try { foo(); } catch { throw; } try { bar(); } catch(E) {throw new Exception(E.message); } } (...) try { MyMethod (); } catch (IOException ex) { Console.WriteLine ("Error with I/O"); // [1] } catch (Exception ex) { Console.WriteLine ("Other error"); // [2] } |
如果
第二个示例将重置异常的堆栈跟踪。第一个最准确地保留了异常的起源。另外,你还打开了原始类型,这是知道实际出了什么问题的关键…如果功能需要第二个-例如,添加扩展信息或使用特殊类型(如自定义"handleableexception")重新包装,则只需确保也设置了InnerException属性!
如果需要,您可以抛出一个新的异常,将原来的异常设置为内部异常。
这里的答案没有一个显示出差异,这可能有助于人们努力理解差异。考虑这个示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | using System; using System.Collections.Generic; namespace ExceptionDemo { class Program { static void Main(string[] args) { void fail() { (null as string).Trim(); } void bareThrow() { try { fail(); } catch (Exception e) { throw; } } void rethrow() { try { fail(); } catch (Exception e) { throw e; } } void innerThrow() { try { fail(); } catch (Exception e) { throw new Exception("outer", e); } } var cases = new Dictionary<string, Action>() { {"Bare Throw:", bareThrow }, {"Rethrow", rethrow }, {"Inner Throw", innerThrow } }; foreach (var c in cases) { Console.WriteLine(c.Key); Console.WriteLine(new string('-', 40)); try { c.Value(); } catch (Exception e) { Console.WriteLine(e.ToString()); } } } } } |
产生以下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Bare Throw: ---------------------------------------- System.NullReferenceException: Object reference not set to an instance of an object. at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12 at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19 at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64 Rethrow ---------------------------------------- System.NullReferenceException: Object reference not set to an instance of an object. at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35 at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64 Inner Throw ---------------------------------------- System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object. at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12 at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43 --- End of inner exception stack trace --- at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47 at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64 |
如前面的答案所示,裸抛出清楚地显示了失败的原始代码行(第12行),以及异常发生时调用堆栈中的其他两个活动点(第19行和第64行)。
重新抛出案例的输出显示了问题的原因。当异常像这样重新引发时,异常将不包括原始堆栈信息。请注意,只包括
最后一个案例(innerthrow)是最详细的,包含的信息比上述任何一个都多。因为我们正在实例化一个新的异常,所以我们有机会添加上下文信息(这里是"外部"消息,但我们也可以在新异常上添加到.data字典),并保留原始异常中的所有信息(包括帮助链接、数据字典等)。