断言与异常(Assertion Vs Exception)
在日常编程实践中,断言与异常的界限不是很明显,这也使得它们常常没有被正确的使用。我也在不断的与这个模糊的怪兽搏斗,仅写此文和大家分享一下我的个人看法。我想我们还可以从很多角度来区别断言和异常的使用场景,欢迎大家的意见和建议。
异常的使用场景:用于捕获外部的可能错误
断言的使用场景:用于捕获内部的不可能错误
我们可以先仔细分析一下我们在.net中已经存在的异常。
System.IO.FileLoadException
SqlException
IOException
ServerException
首先,我们先不将它们看成异常,因为我们现在还没有在异常和断言之间划清界限,我们先将它们看成错误。
当我们在编码的第一现场考虑到可能会出现文件加载的错误或者服务器错误后,我们的第一直觉是这不是我们代码的问题,这是我们代码之外的问题。
例如下面这段代码
public void WriteSnapShot(string fileName, IEnumerable<DbItem> items)
{
string format = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}";
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.Unicode))
{
...
foreach (var item in items)
{
sw.WriteLine(string.Format(format, new object[]{
item.dealMan,
item.version,
item.priority,
item.bugStatus,
item.bugNum,
item.description}));
}
sw.Flush();
}
}
}
上面的代码在写入文件,很显然会导致IOException。稍微有经验的程序员都会考虑到IO上可能出问题,那我们应该如何处理这个问题呢?在这个上下文中,我们别无它法,只能让这个错误继续往上抛,通知上面一层的调用者,有一个错误发生了,至于上一层调用者会如何处理,不是这个函数要考虑的问题。但在这个函数中,要记得一点,将当前函数中所占用的资源释放了。因此,当我们不能控制的外部错误出现时,我们可以将其作为异常往上抛,这时,我们该使用异常。
现在再来看看断言,我们还是以下面的一段代码为例子。
public Entities.SimpleBugInfo GetSimpleBugInfo(string bugNum)
{ var selector = DependencyFactory.Resolve<ISelector>(); var list = selector.Return<Entities.SimpleBugInfo>(
reader => new Entities.SimpleBugInfo
{
bugNum = reader["bugNum"].ToString(),
dealMan = reader["dealMan"].ToString(),
description = reader["description"].ToString(),
size = Convert.ToInt32(reader["size"]),
fired = Convert.ToInt32(reader["fired"]),
},
"select * from bugInfo",
new WhereClause(bugNum, "bugNum")); Trace.Assert(list != null); if (list.Count == )
return null;
else
return list[]; }
当我贴出这段代码时,心情有些坎坷,因为我本人在这里也纠结了很久,这也是我一直没有将断言和异常划清界线的原因之一。
首先我们来回顾一下之前定义的断言使用场景:内部不可能发生的错误。
selector.Return这段代码是不是内部代码?如果我们能够修改Return中的代码,说明它是内部代码;反之,说明它是外部代码。对于内部代码,我们可以用断言来保护其逻辑的不变性,当断言被触发时,我们就可以确信是内部代码的错误,我们应该立即修复。
再纠结一下,假设Return是外部代码,我们没有办法去修改它。那么上面的代码可以有两种写法(如果你有更多的想法,请赐教)。
第一种,直接抛出异常。
If(list == null)
{
throw new NullReferenceException();
}
第二种,调整代码。
if(list == null || list.Count == )
{
return null;
}
else
{
return list[];
}
当然,还有一种就是什么也不做,让代码执行下去直至系统为你抛出空引用错误。但这种做法违背了防卸性编程的原则,我们总是应行尽早或离错误的发生地最近的地方处理错误,避免错误数据流向系统的其它地方,产生更加严重的错误。
总结
对异常或断言的使用取决于你要防卸的是一个内部错误还是外部错误以及你认为它是一个内部错误或外部错误。如果你决定防卸一个内部错误,那请果断使用断言,反之,请使用异常。
参见:
.net 的异常继承树(http://msdn.microsoft.com/en-us/library/z4c5tckx(v=vs.110).aspx)
原代码来至于我的TeamView开源项目(http://teamview.codeplex.com)
巜从小工到大师》
断言与异常(Assertion Vs Exception)的更多相关文章
- Python 断言和异常
Python 断言和异常 Python断言 断言是一种理智检查,当程序的测试完成,可以将其打开或关闭.断言的最简单方法就是把它比作raise-if语句(或更加准确,raise-if-not声明).一个 ...
- 用Assert(断言)封装异常,让代码更优雅(附项目源码)
有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...
- NET环境下的未处理异常(unhandled exception)的解决方案
NET环境下的未处理异常(unhandled exception )的解决方案 .Net 框架提供了非常强大的异常处理机制,同时对一些非托管代码很难控制的系统问题比如指针越界,内存泄漏等提供了很好的解 ...
- java异常—检查异常(checked exception)和未检查异常(unchecked exception)
网易面试要我画异常的结构图,什么是检查异常,什么是非检查异常,我当时的表情是这样的,.我看过,忘了.没办法,继续看,写博客掌握. 先来看看异常的结构图,建议你结合JDK一起看. 可以看出异常的家族势力 ...
- 检查型异常(Checked Exception)与非检查型异常(Unchecked Exception)
这两个概念看了忘,碰着了又看,老是傻傻的分不清楚,今天把心得结合从网上搜的资料简单整理一下,希望帮自己明确区分开这两个概念,并牢牢的记住 1.检查型异常(Checked Exception) 个人理解 ...
- 2019-2-21.NET中异常类(Exception)
.NET中异常类(Exception) 异常:程序在运行期间发生的错误.异常对象就是封装这些错误的对象. try{}catch{}是非常重要的,捕获try程序块中所有发生的异常,如果没有捕获异常的话, ...
- 应用程序发生异常 unknown software exception (0xc00000fd)... - 栈溢出(Stack overflow)
今天在写程序的时候,弹出这样的提示对话框: 应用程序发生异常 unknown software exception (0xc00000fd): 相关代码是这样,在一个函数中读取一个csv文件,先根据这 ...
- java 异常和异常处理Exception
Java Exception: 1.Error 2.Runtime Exception 运行时异常3.Exception 4.throw 用户自定义异常 异常类分两大类型:Error类代表了编译和系统 ...
- Java 异常(Java Exception)
Java异常 异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类 ...
随机推荐
- CentOS 7 网络配置
Virtual box 安装了CentOS 7最小模式后马上用ifconfig命令查看网络情况,发现该命令不存在. [root@centos1 ~]# ifconfig -bash: ifconfig ...
- 获取进程CPU占用率
获取进程CPU占用率 // 时间转换 static __int64 file_time_2_utc(const FILETIME* ftime) { LARGE_INTEGER li; li.LowP ...
- thinphp框架的项目svn重新检出后的必备配置
刚刚试着去了解thinkphp框架,在这里做一些笔记,后续有新的总结会更新到这里,如有错误与遗漏,望大家指正. 用thinkphp框架的项目,在用svn重新检出之后,需要进行一些基本配置,方可在本地打 ...
- SQL Server 默认跟踪(Default Trace)
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 基础知识(Rudimentary Knowledge) 查看默认跟踪信息(Default Tr ...
- LINQ系列:LINQ to XML操作
LINQ to XML操作XML文件的方法,如创建XML文件.添加新的元素到XML文件中.修改XML文件中的元素.删除XML文件中的元素等. 1. 创建XML文件 string xmlFilePath ...
- Pipedata3d - Welding Neck Flange
Pipedata3d - Welding Neck Flange eryar@163.com Abstract. Pipedata3d show piping component data in ta ...
- OpenCascade Eigenvalues and Eigenvectors of Square Matrix
OpenCascade Eigenvalues and Eigenvectors of Square Matrix eryar@163.com Abstract. OpenCascade use th ...
- datatable去重
两种方法1 数据库直接去除重复select distinct * from 表名去除了重复行distinct 2 对 DataTable直接进行操作DataTable dt=db.GetDt(&quo ...
- 纯CSS照片墙
css中transform参考CSS3属性transform详解之(旋转:rotate,缩放:scale,倾斜:skew,移动:translate 效果图:
- 前端学PHP之运算符
× 目录 [1]总括 [2]算术运算符 [3]赋值运算符[4]位运算符[5]比较运算符[6]错误控制[7]逻辑运算符[8]字符串连接[9]数组运算符 前面的话 运算符是可以通过给出的一或多个表达式来产 ...