Cleaner, more elegant, and wrong(msdn blog)
Cleaner, more elegant, and wrong
Just because you can't see the error path doesn't mean it doesn't exist.
Here's a snippet from a book on C# programming, taken from the chapter on how great exceptions are.
try {
AccessDatabase accessDb = new AccessDatabase();
accessDb.GenerateDatabase();
} catch (Exception e) {
// Inspect caught exception
} public void GenerateDatabase()
{
CreatePhysicalDatabase();
CreateTables();
CreateIndexes();
}Notice how much cleaner and more elegant [this] solution is.
Cleaner, more elegant, and wrong.
Suppose an exception is thrown during CreateIndexes(). The GenerateDatabase() function doesn't catch it, so the error is thrown back out to the caller, where it is caught.
But when the exception left GenerateDatabase(), important information was lost: The state of the database creation. The code that catches the exception doesn't know which step in database creation failed. Does it need to delete the indexes? Does it need to delete the tables? Does it need to delete the physical database? It doesn't know.
So if there is a problem creating CreateIndexes(), you leak a physical database file and a table forever. (Since these are presumably files on disk, they hang around indefinitely.)
Writing correct code in the exception-throwing model is in a sense harder than in an error-code model, since anything can fail, and you have to be ready for it. In an error-code model, it's obvious when you have to check for errors: When you get an error code. In an exception model, you just have to know that errors can occur anywhere.
In other words, in an error-code model, it is obvious when somebody failed to handle an error: They didn't check the error code. But in an exception-throwing model, it is not obvious from looking at the code whether somebody handled the error, since the error is not explicit.
Consider the following:
Guy AddNewGuy(string name)
{
Guy guy = new Guy(name);
AddToLeague(guy);
guy.Team = ChooseRandomTeam();
return guy;
}
This function creates a new Guy, adds him to the league, and assigns him to a team randomly. How can this be simpler?
Remember: Every line is a possible error.
- What if an exception is thrown by "new Guy(name)"?
-
Well, fortunately, we haven't yet started doing anything, so no harm done.
- What if an exception is thrown by "AddToLeague(guy)"?
-
The "guy" we created will be abandoned, but the GC will clean that up.
- What if an exception is thrown by "guy.Team = ChooseRandomTeam()"?
-
Uh-oh, now we're in trouble. We already added the guy to the league. If somebody catches this exception, they're going to find a guy in the league who doesn't belong to any team. If there's some code that walks through all the members of the league and uses the guy.Team member, they're going to take a NullReferenceException since guy.Team isn't initialized yet.
When you're writing code, do you think about what the consequences of an exception would be if it were raised by each line of code? You have to do this if you intend to write correct code.
Okay, so how to fix this? Reorder the operations.
Guy AddNewGuy(string name)
{
Guy guy = new Guy(name);
guy.Team = ChooseRandomTeam();
AddToLeague(guy);
return guy;
}
This seemingly insignificant change has a big effect on error recovery. By delaying the commitment of the data (adding the guy to the league), any exceptions taken during the construction of the guy do not have any lasting effect. All that happens is that a partly-constructed guy gets abandoned and eventually gets cleaned up by GC.
General design principle: Don't commit data until they are ready.
Of course, this example was rather simple since the steps in setting up the guy had no side-effects. If something went wrong during set-up, we could just abandon the guy and let the GC handle the cleanup.
In the real world, things are a lot messier. Consider the following:
Guy AddNewGuy(string name)
{
Guy guy = new Guy(name);
guy.Team = ChooseRandomTeam();
guy.Team.Add(guy);
AddToLeague(guy);
return guy;
}
This does the same thing as our corrected function, except that somebody decided that it would be more efficient if each team kept a list of members, so you have to add yourself to the team you intend to join. What consequences does this have on the function's correctness?
Cleaner, more elegant, and wrong(msdn blog)的更多相关文章
- Cleaner, more elegant, and wrong(翻译)
Cleaner,more elegant,and wrong 整洁,更优雅,但是错的 并不是因为你看不到错误的产生路径就意味着它不存在. 下面是C#编程书中的一个片段,摘自关于异常处理的章节. try ...
- 树状数组的笔记√(hzwer blog)
int lowbit(int x) { return x&(-x); } lowbit()的返回值就是 2^k 次方的值. 求数组的和的算法: (1)首先,令sum=0,转向第二步: (2)接 ...
- Alpha 任务状态总览(持续更新)
Alpha 任务状态总览(持续更新) Part 0 · 简 要 目 录 Part 1 · 流 程 Part 2 · 总 任 务 量 安 排 Part 3 · 爬 虫 任 务 Part 4 · 接 口 ...
- Cleaner, more elegant, and harder to recognize (msdn blog)
It appears that some people interpreted the title of one of my rants from many months ago, "Cle ...
- Cleaner, more elegant, and harder to recognize(翻译)
Cleaner, more elegant, and harder to recognize 更整洁,更优雅,但更难识别 看来,有些人把我几个月前一篇文章的标题"Cleaner,more e ...
- js 正则表达式 转至(七郎's Blog)
//匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线 var re =new RegExp("^[a-zA-Z][a-zA-Z0-9_]{5,19}$"); if( ...
- Visual Studio 2010 简体中文旗舰、专业版(MSDN原版下载)
Visual Studio 2010 简体中文旗舰.专业版(MSDN原版下载)(Visual Studio 2010 ultimate professional x86 dvd)2010[光盘镜像]- ...
- Hibernate 配置 转(http://blog.csdn.net/b671900/article/details/39156065)
做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么 ...
- HDU 5813 Elegant Construction(优雅建造)
HDU 5813 Elegant Construction(优雅建造) Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65 ...
随机推荐
- ssh中Hibernate懒加载,session问题的学习与理解
交代本项目中要求获取session的方式如下: public Session getCurrentSession() { // 增删改使用的session,事务必须是开启的(Required,即pro ...
- 51nod 1058 N的阶乘的长度 位数公式
1058 N的阶乘的长度基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注输入N求N的阶乘的10进制表示的长度.例如6! = 720,长度为3.Input输入N( ...
- javascript面向对象系列第四篇——OOP中的常见概念
前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...
- 移动端H5制作安卓和IOS的坑 持续更新...
移动端H5制作安卓和IOS的坑 持续更新... 前言:最近参加公司的H5页面创意竞赛,又遇到不少页面在不同系统上的坑.踩坑之余,觉得很多之前遇到的知识点都忘了,索性开一篇博文,把这些坑都统一归纳起来, ...
- 游标遍历所有数据库循环执行修改数据库的sql命令
MSSQL数据库服务器上有很多类似的数据库,需要将这些数据库统一修改其中的某些表或者某些命令,那么就会想到用游标来遍历. 先来说思路: 1,首先需要查询出所有的数据库: select [name] f ...
- jQuer __Ajax DOM
链接:在线jQueryhttp://www.bootcdn.cn 一.each(遍历) $("ul li").each(function(index,value){ ale ...
- 10.0.0.55_12-16训练赛部分writeup
0x1 - MISC MISC100 一张帅行的照片 目测是图片隐写,但是binwalk并没有出来,应该是对文件头进行了修改 010editor查看一下,发现在jpg文件尾之后还有大量的数据 而且在灰 ...
- Tomcat (安装及web实现 基础)
Tomcat服务器配置 安装:解压对应的版本就行 注意;不要把Tomcat放到有中文的和有空格的目录中 验证是否安装成功:进入安装盘的安装文件的bin目录下 执行startup bat 成功 80 ...
- TP3.2 图片上传及缩略图
基于TP自带的上传文件的类, Think/Upload.class.php 设置表单的enctype属性 下面是上传的具体方法 /** * 图片上传处理 * @param [String] $path ...
- Hibernate中使用@Lob 注解保存String[] 问题
Hibernate中使用@Lob 注解保存String[] 问题 在Hibernate注解中怎样你想保存一个字段为String数组类型.假设你想尝试保存为clob类型的话,普通情况下为定义为: @En ...