这个问题在这里已有答案:

  • 捕获和重新抛出.NET异常的最佳实践 11答案

我有一个问题,源于我的伙伴以不同于我的方式做事。

这样做更好:

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

或这个:

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

他们做同样的事情吗? 这个比那个好吗?


#1楼

我知道这是一个老问题,但我会回答它,因为我不得不在这里不同意所有的答案。

现在,我同意大多数时候你要么做一个简单的throw ,尽可能多地保存关于出错的信息,或者你想抛出一个新的异常,可能包含它作为内部异常,或不,取决于您想要了解导致它的内部事件的可能性。

但有一个例外。 在某些情况下,方法将调用另一个方法,并且在内部调用中导致异常的条件应被视为外部调用上的相同异常。

一个示例是使用另一个集合实现的专用集合。 假设它是一个包含List<T>但是拒绝重复项的DistinctList<T>

如果有人在您的集合类上调用ICollection<T>.CopyTo ,它可能只是在内部集合上直接调用CopyTo (例如,所有自定义逻辑仅应用于添加到集合或设置它)。 现在,该调用将抛出的条件与您的集合应该抛出的条件完全相同,以匹配ICollection<T>.CopyTo的文档。

现在,你可能根本就没有抓住这个执行,让它通过。 这里虽然用户在调用DistinctList<T>上的内容时从List<T>获得异常。 不是世界末日,但您可能希望隐藏这些实现细节。

或者您可以自己检查:

public CopyTo(T[] array, int arrayIndex)
{if(array == null)throw new ArgumentNullException("array");if(arrayIndex < 0)throw new ArgumentOutOfRangeException("arrayIndex", "Array Index must be zero or greater.");if(Count > array.Length + arrayIndex)throw new ArgumentException("Not enough room in array to copy elements starting at index given.");_innerList.CopyTo(array, arrayIndex);
}

这不是更糟糕的代码,因为它是样板文件,我们可以从CopyTo其他实现中复制它,它不是一个简单的传递,我们必须自己实现它。 仍然,它不必要地重复将在_innerList.CopyTo(array, arrayIndex)完成的完全相同的检查,所以它添加到我们的代码中的唯一的东西是6行,其中可能存在错误。

我们可以检查并包装:

public CopyTo(T[] array, int arrayIndex)
{try{_innerList.CopyTo(array, arrayIndex);}catch(ArgumentNullException ane){throw new ArgumentNullException("array", ane);}catch(ArgumentOutOfRangeException aore){throw new ArgumentOutOfRangeException("Array Index must be zero or greater.", aore);}catch(ArgumentException ae){throw new ArgumentException("Not enough room in array to copy elements starting at index given.", ae);}
}

对于可能存在错误的新代码而言,情况更糟。 而且我们没有从内心异常中获得一些东西。 如果我们将null数组传递给此方法并接收ArgumentNullException ,我们将不会通过检查内部异常并了解对_innerList.CopyTo的调用是否传递了一个空数组并抛出ArgumentNullException来学习任何东西。

在这里,我们可以做我们想要的一切:

public CopyTo(T[] array, int arrayIndex)
{try{_innerList.CopyTo(array, arrayIndex);}catch(ArgumentException ae){throw ae;}
}

如果用户使用不正确的参数调用它,我们期望必须抛出的每个异常将被重新抛出正确抛出。 如果这里使用的逻辑中存在一个错误,那么它就是两行中的一行 - 要么我们错误地决定这种方法是否有效,或者我们错误地将ArgumentException作为查找的异常类型。 这是catch块可能拥有的唯一两个bug。

现在。 我仍然同意大多数时候你要么普通throw; 或者您想构建自己的异常,以便从相关方法的角度更直接地匹配问题。 像上面这样的情况,像这样的重新投掷更有意义,还有很多其他情况。 举一个非常不同的例子,如果使用FileStreamXmlTextReader实现的ATOM文件读取器收到文件错误或无效的XML,那么它可能想要从这些类中获得完全相同的异常,但它应该看起来调用者是AtomFileReader抛出FileNotFoundExceptionXmlException ,因此他们可能是类似重新抛出的候选者。

编辑:

我们也可以将两者结合起来:

public CopyTo(T[] array, int arrayIndex)
{try{_innerList.CopyTo(array, arrayIndex);}catch(ArgumentException ae){throw ae;}catch(Exception ex){//we weren't expecting this, there must be a bug in our code that put//us into an invalid state, and subsequently let this exception happen.LogException(ex);throw;}
}

#2楼

您应该始终使用以下语法来重新抛出异常,否则您将踩踏堆栈跟踪:

throw;

如果您打印“throw ex”产生的跟踪,您将看到它在该语句上结束,而不是在异常的真实来源。

基本上,使用“throw ex”应被视为刑事犯罪。


#3楼

第一个保留异常的原始堆栈跟踪,第二个跟踪当前位置。

因此第一个是BY FAR越好。


#4楼

第一个更好。 如果您尝试调试第二个并查看调用堆栈,您将看不到原始异常的来源。 如果你真的需要重新抛出,有一些技巧可以保持调用堆栈的完整性(尝试搜索,之前已经回答)。


#5楼

我的偏好是使用

try
{
}
catch (Exception ex)
{...throw new Exception ("Put more context here", ex)
}

这样可以保留原始错误,但允许您放置更多上下文,例如对象ID,连接字符串等。 我的异常报告工具通常会有5个链式异常报告,每个报告更多细节。


#6楼

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

在第一个示例中,将更改StackTrace以反映当前方法。

例:

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

#7楼

你应该总是使用“扔”; 重新抛出.NET中的异常,

请参阅此处, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx

基本上MSIL(CIL)有两条指令 - “throw”和“rethrow”以及C#的“throw ex”; 被编译成MSIL的“throw”和C#的“throw”。 - 进入MSIL“重新抛出”! 基本上我可以看到“throw ex”覆盖堆栈跟踪的原因。


#8楼

这取决于。 在调试版本中,我希望尽可能少地查看原始堆栈跟踪。 在那种情况下,“扔;” 符合条件。 但是,在发布版本中,(a)我想记录包含原始堆栈跟踪的错误,并且一旦完成,(b)重新设计错误处理以使用户更有意义。 这里的“抛出异常”是有道理的。 确实,重新抛出错误会丢弃原始堆栈跟踪,但是非开发人员无法看到堆栈跟踪信息,因此可以重新抛出错误。

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

问题措辞的方式,点击“投掷:”与“投掷前”; 让它有点像红鲱鱼。 真正的选择是在“投掷”之间 和“抛出异常”,“扔前”; 是一个不太可能的特殊情况“抛出异常”。


#9楼

我发现如果在捕获它的同一方法中抛出异常,则不保留堆栈跟踪,因为它的价值。

void testExceptionHandling()
{try{throw new ArithmeticException("illegal expression");}catch (Exception ex){throw;}finally{System.Diagnostics.Debug.WriteLine("finally called.");}
}

在C#中重新抛出异常的正确方法是什么? [重复]相关推荐

  1. 【转】Java中获取文件大小的正确方法

    [转]Java中获取文件大小的正确方法 本文出处:http://blog.csdn.net/chaijunkun/article/details/22387305,转载请注明.由于本人不定期会整理相关 ...

  2. python中自定义错误_在现代Python中声明自定义异常的正确方法?

    在现代Python中声明自定义异常类的正确方法是什么?我的主要目标是遵循其他异常类所具有的任何标准,以便(例如)由捕获异常的任何工具打印出异常中包含的任何额外字符串. 所谓"现代Python ...

  3. python中类的定义方法_在Python中定义类变量的正确方法

    这两种方法都不一定正确或不正确,它们只是两种不同的类元素:方法__init__之外的元素是静态元素:它们属于类. __init__方法中的元素是对象(self)的元素:它们不属于类. 使用一些代码可以 ...

  4. python初始化方法对应的变量是全局变量嘛_在Python中初始化全局变量的正确方法...

    我有一个初始化一些全局变量的 Python模块;这样的事情: #!/usr/bin/env python import re """My awesome python l ...

  5. C++ 中重载 + 操作符的正确方法

    用户定义的类型,如:字符串,日期,复数,联合体以及文件常常重载二元 + 操作符以实现对象的连接,附加或合并机制.但是要正确实现 + 操作符会给设计,实现和性能带来一定的挑战.本文将概要性地介绍如何选择 ...

  6. Java中获取文件大小的正确方法

    本文出处:http://blog.csdn.net/chaijunkun/article/details/22387305,转载请注明.由于本人不定期会整理相关博文,会对相应内容作出完善.因此强烈建议 ...

  7. C++中实现Singleton的正确方法

    如果某个类管理了系统中唯一的某种资源,那么我们只能创建该类的一个实例,此时用到singleton设计模式(后面为了简化将省略"设计模式"四个字)就比较合适了.然而,如果不注意实现方 ...

  8. C++中申请内存的正确方法

    申请内存的方法不合理: 合理: 解析:检查内存泄露的最好办法,就是检查完全配对的申请和释放(在代码的同一层次),在函数中申请而在外部释放,将导致代码的一致性变差,难以维护.而且,你写的函数不一定是你自 ...

  9. python oop 继承_关于oop:使类数据在python中可继承的正确方法是什么?

    我是Python的新手,来自Perl领域. 我正在尝试确定关于类数据的存储和访问的最佳实践,以便它可以被子类继承并可能进行扩展.阅读Python 2.7文档(我确实使用2.6),深入研究Python和 ...

最新文章

  1. mysql以及mysql bench安装教程
  2. 抢红包算法 c语言,红包分配算法,抢红包算法
  3. 如何在javascript中使用多个分隔符分割字符串?
  4. python echo服务器_python常用框架 echo server 的测试
  5. how to render AET extension field as code list
  6. 有空研究这篇http://blog.csdn.net/studyvcmfc/article/details/7720258 研究后写篇记录
  7. 草稿 9206 1128需处理
  8. 《和平精英》玩跨界,特斯拉主题店超级充电站现身海岛
  9. Linux下tar压缩与解压缩文件
  10. 博文视点大讲堂第33期
  11. C++ boost::upgrade_lock upgrade_to_unique_lock 升级锁 是什么 怎么用
  12. 计算机键盘灯不亮原因,计算机键盘灯不亮,鼠标灯亮的原因和解决方法
  13. Android进阶——性能优化之APP启动速度优化实战总结(三)
  14. 现代软件工程讲义 7 设计阶段 Spec
  15. Stderr: VBoxManage.exe: error: VT-x is not available (VERR_VMX_NO_VMX) VBoxM
  16. 0002 c语言 字母排序
  17. 一个流和百亿级的表的join
  18. mybatis实现一对多有几种方式_两件塑胶件连接,有哪几种方式实现?
  19. 07-07-Exchange Server 2019-配置-脱机地址簿
  20. EasyRules动态规则实现

热门文章

  1. dex文件结构(三):dex文件差分包分成
  2. 【Android游戏开发十五】关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记! .
  3. 微信小游戏开发教程-游戏实现3
  4. swift_010(Swift 的可选类型)
  5. html5插件教程,HTML5教程 | HTML5 time元素
  6. python 地址模糊匹配_使用python处理selenium中的xpath定位元素的模糊匹配问题
  7. 用存储过程创建的分页
  8. apache环境下配置服务器支持https
  9. HTTP [TCP Retransmission] Continuation or non-HTTP traffic[Packet size limited during capture]
  10. [转]Oracle DB 复制数据库