有没有真正的世界理由使用throw ex?
在C#中, throw ex
几乎总是错误的,因为它会重置堆栈跟踪。
我只是想知道,这有什么现实世界吗? 我能想到的唯一原因是隐藏封闭库的内部,但这是一个非常薄弱的原因。 除此之外,我从未在现实世界中遇到过。
编辑:我的意思是throw ex
,就像抛出完全相同的exception而被捕获但是有一个空的堆栈跟踪,就像完全错误一样。 我知道throw ex必须作为一个语言结构存在,以允许抛出一个不同的exception( throw new DifferentException("ex as innerException", ex)
),并且只是想知道是否有一个现场,其中一个throw ex
没有错。
没有正当理由重新抛出exception对象,即’throw ex’。
它是一种语言编译器function,虽然在实践中没有增加任何价值,但它没有增加任何价值。 这是一种类似的情况,能够编写代码来访问空引用的成员 – 它当然可能但没有价值,例如:
//Possible but not useful. object ref1 = null; ref1.ToString();
能够重新抛出exception对象是不幸的,并且经常被新手和有经验的编码人员误解,直到你在生产中得到一个未处理的exception,并记录了截断的堆栈跟踪。
有一种微弱的感觉,它可以用来故意隐藏堆栈跟踪信息,但抛出一个新的exception将是正确的方法来做到这一点。
我甚至可以说能够重新抛出exception对象(即’throw ex’)是一个设计缺陷 – 这样做太容易做错了。 但是,我怀疑这是因为性能原因而在编译器中进行设计权衡,因为它会产生开销来validation’throw ex’不是’re-throw’。 我敢肯定有很多这样的权衡。
我从未见过它是故意使用的,但这当然没有任何意义。
让我们来看看替代方案:
catch(Exception ex) { // do stuff (logging) throw; // a) continue ex throw new SomeException("blah", ex); // b) wrap throw new SomeException("blah"); // c) replace throw ex; // d) reset stack-trace }
c)和d)都在放弃堆栈跟踪,d)唯一的’优势’我能看到的是throw ex;
保留ex
的确切类型和可能的额外属性(SQL错误)。
那么有没有想要保留除堆栈跟踪之外的所有exception信息的情况? 不正常,但有些猜测:
如果你停下来思考它, throw ex
实际上经常使用 – 除了一个未命名的局部变量。 (重新)设计语言将非常困难,因此:
throw new ArgumentException();
是有效的,但是
var ex = new ArgumentException(); throw ex;
无效(然后扩展它以跟踪更复杂的变量赋值)。 即throw ex
是throw语句的“正常”forms,但在重新抛出已经捕获的exception时通常是错误的。
throw ex
只是一个错误或由不知道或忘记throw;
人做出的错字 throw;
。
它可能仅在一种情况下,在其答案中由其他人指出:您不希望将正确的堆栈跟踪发送给调用者的情况,但您仍希望保留先前抛出的exception类型。 在实践中,我很难想象有人会需要它的情况,并且不会使用throw new SomeCustomException(...)
。
FxCop规则CA2200 RethrowToPreserveStackDetails
以相同的方式进行,邀请您使用throw;
正确地重新抛出exception throw;
:
try { // ... } catch (SomeException ex) { Logger.AddException(ex); throw; }
以下是重新抛出现有exception对象的两个实际应用程序:
reflection
通过reflection调用代码时,抛出的任何exception都将包含在TargetInvocationException中 。 但是你可能希望/需要处理反映“障碍”之外的exception。 在这种情况下,包装将使exception处理代码复杂化。 相反,您可以解开原始exception并重新抛出。
如果您使用的是.NET 4.5+,则可以使用ExceptionDispatchInfo来保留原始堆栈跟踪:
MethodInfo someMethod = ... try { someMethod.Invoke(); } catch (TargetInvocationException e) { ExceptionDispatchInfo.Capture(e.InnerException).Throw(); }
任务API
在.NET Task API中,在执行任务期间抛出的exception包含在AggregateException中 。 当使用async / await时,框架将在封面下执行展开,以便抛出原始exception而不是包装器AggregateException。
除了在自动解包时需要重新抛出现有exception的BCL代码之外,有些情况下您无法使用async / await,因此需要手动解包和重新抛出。 有关此实例,请查看Stephen Clearys优秀AsyncEx项目中AsyncContext实现中TaskExtensions.WaitAndUnwrapException的内部用法。
您可能希望记录exception,记录它然后将其作为’throw ex’抛出到上层。 您可能还希望在此层中进行日志记录,但这可能与您获得exception的层无关,或者您可能不需要该exception的详细信息,因为您已经记录了它。
让我们说你有:
上述就是C#学习教程:有没有真正的世界理由使用throw ex?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
Public int GetAllCustomers() { try { return data.GetAllCustomers() } catch() { Logger.log("Error calling GetAllCustomers"); } } //data Public static int GetAllCustomers() { try { //db operations... } catch(Exception ex) { Logger.log(ex.Stacktrace); throw ex; } }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1020739.html