异常处理(100分)

  • 主题发起人 主题发起人 爱如泣血
  • 开始时间 开始时间

爱如泣血

Unregistered / Unconfirmed
GUEST, unregistred user!
请问Delphi的异常处理有哪些结果?
 
这样问问题的人 应该先去看 DELPHI 入门书了。
 
这个要不要看一下,
对错误的态度
天堂鸟自由空间©2000-2001 版权所有
转载请保持文档的完整性
mailto:mymailwh@263.net
近一年来因为工作的关系看很多其他程序员的代码,学习了不少东西,但同时也发现很
多问题,其中我遇到的最多的就是对错误的处理态度。
1) 从不拦截错误;
这可能是最原始且是最不好的行为,出现这种情况的一般有两种人:其一新手他们不了解什么情况下会出错,或者根本就不知道要这么处理;其二这种人总是认为自己的程序肯定100%不会出现问题,因为他们坚信自己的代码考虑了一切可能的情况,这种理解我认为是非常危险的,翻翻你的代码,看看是否考虑了以下常见的情况:
l 在只允许输入数字的文本框里你拦截了键盘事件,但用户用右键粘贴了文本后你的
程序正常吗?
l 磁盘空间不足、目录只读、没有权限、目录名中有小数点、系统采用了短日期甚至
不标准的格式;
l 明明事先检查了磁盘空间足够,可用户偏使用了什么磁盘配额,还是磁盘空间不足;
l 用户在你一段长时间的操作工程中等的不耐烦强行关机后重新运行你的这段程序;
(当然切断电源除外)
l 你相信不相信原本不能重复的记录,居然会莫名其妙的重复?
。。。。。。。
你所想象不到的情况太多了,所以说你永远不可能考虑所有的情况。
2) 总是拦截错误,而不去处理错误;
这种情况和第一种情况恰恰相反,他会不厌其烦的在每个过程中都添加try。。。。
except。。。。end
,然后出错的话报一个MsgBox框出来,我相信99%的程序员基本上都是
这么做的,也许马上就有人立即站起来说:你刚才还说不可能考虑每一种情况,所以要拦错,为什么马上反悔了呢?别急,听我说:我们做的大多数都是跟数据库打交道的,数据库的数据强调的是一致性和有效性。现在首先看下面的一段代码:
try
try
tempquery.execsql;
except
begin
……
abort;
end;
end;
finally
tempquery.free;
end;
很典型,上面这段代码就是这样。虽然拦截了错误单是已经有些数据已经生成了,如果仅仅是取消下面的操作,那么已经生成的数据势必成为垃圾数据存在于数据库中;这是我们都不希望看到的。这就是我想要说的,不但要防止出错;而且在出错以后要想办法回复到出错以前的状态。下面的这段就不错:
App_RKD.Table_ZB.Database.StartTransaction;
try
code := F_JKCZ(VU_RYMC, Get_Current_Day);
case code of
0: ;
else abort;
end;
App_RKD.Table_ZB.Database.Commit;
DEC(VI_Pass);
except
App_RKD.Table_ZB.Database.RollBack;
现在,我再用一个例子来说明一下:
我们假设有4个过程A,B,C,D,其中A调用了B,B有调用了C,C又调用了D,如果我们在每
个子过程中都拦截了错误,那么如果D发生了错误,程序将报告发生一个错误,显然这时D
退出后,C其后的代码就不应该执行了,似乎他现在唯一的办法只有通过D返回False来表示
失败,他才知道底层失败了,不能继续执行了,同样的道理C和B都要返回False来取消任务。
天啦,这岂不是要没有过程都要写成返回True和False了,看看你的程序,这可能吗?
而且你将遇到一个非常尴尬的局面,你调用任何一个函数都要这样调用:
If not B Then
A := False
我想你肯定觉得不爽,不仅如此你还有一个致命的问题:最上层的程序(注意是程序而
不是用户)根本不知道底层什么地方失败了,什么原因失败了,他唯一知道了事就是失败了!啊,真惨。
3) 对错误的不同态度;
假设一个函数原型如下(此例子是用C++编写;但对于其他编程语言,它的思想精髓照样
适用):
int DoSomeThing(char* pParam)
{
...
}
关于这个问题,大概是所有的程序员都会遇到的。
事先约定好参数pParam不能为NULL,但为了防止调用者错误传递NULL,你需要在你的函
数里做判断处理。现在有下面的这几种防错方式:
(a) if (!pParam)
return 0;
这是很多初级程序员常常采取的一种方式。返回值设为0。因为函数的返回值往往是计
算的结果,不赞成把错误标志值和计算结果混在一起使用,容易造成使用者的误会。当然,在很多unix函数中,由于历史原因,还存在很多这样子的函数,所以需要指出,不要沿用这
种方式。
(b) if (!pParam)
return ERROR_PARAM;
b比a稍微好一点点,返回了一个常量或者预定义的宏。从返回值的字面上,调用者能
知道发生了什么错误,但是,这也不是一种好的方法,因为它只能仅仅知道什么错误,程序
还是照样运行。
(c) if (!pParam)
pParam = "";
这是最不好的方式。直接给pParam赋予空字符串,然后继续函数过程,这容易造成不可
预料的后果,是程序不稳定的根源所在。
(d) if (!pParam)
throw EXCEPTION_ERROR_PARAM;
如果没人catch这个exception,其结果就跟f一样,按bug处理,dump core留下一stack
trace。如果有人catch,那就按运行错误处理......但是返回一特初值表示错误,只是将错
误上交,掩耳盗铃而已。最终总得有个人assert,messagebox,throw exception,perror+exit,
或别得什么的。既然已经是约定,就干脆付起责任。
同时有一种反对d的理由:这就像你用人,却不相信人一样,偏要try,catch防范他。其实
那个错是自己造成的,如果看到异常就容易不检讨自己。
(e) if (!pParam)
MessageBox(...);
这是一种比较可笑的方式,当然也有不少人用。MessageBox是直接弹出一个对话框,告
诉使用者,出错了。但是并不做任何处理,程序继续往下执行,直到出错崩溃。呵呵
(f) assert(!pParam);
因为非NULL是约定,所以可以确定是调用者的问题,f可以明确地指出这一点,防止错
误扩散。我的附加说明: 防止错误扩散的意思是,如果用其他方式,比如throw exception
的方式,这个异常不一定会在调用此函数的上一层被捕捉到,可能会被继续抛出直到最上一
层或者直到在某一层被catch到,这样的话,错误就会距离发生地点很远,扩散开来。这一
观点,代表了一大部分的程序员的观点。
还有一种观点;主张选f+d, 好处如下:
l 以最激烈的方式,充分暴露调用都的错误!能及时修改BUG
l 便于调试,问题出现后,直接到事故现场。比120还快!
如果在现实中,测试没有能找到所有的BUG,那可能就要用异常来帮忙了!但是,提出来
希望大家注意:异常不是捕获了就完成任务了,而要对于不同的情况,采取不同的处理办法,千万不能只是捕获,而不做任何处理,那样和不捕获异常没有任何区别。
以上是我对错误的态度,说的很杂乱,请大家不要介意,我非常希望大家能够一起谈谈
这个问题。
 
try except try finally!!!
 
var
x,y:integer;
i:extended;
begin
x:=11;
y:=0;
i:=450;
try
i:=x/y;
showMessage(floatToStr(i));
except
showmessage('can not divide by zero');
end;
end;
楼主还不明白吗?
代码是没有问题,
问题在于,你的那个i在程序的其他地方没有用到
而被编译器的优化功能给抛弃了,也就是他根本没有被执行,当然就没有异常可抓了
 
不明白最后wqhatnet讲的是什么。
 
后退
顶部