C
chinaplate
Unregistered / Unconfirmed
GUEST, unregistred user!
5.接管所有的异常
最初接触Exception也是在Delphi中,那时很不明白,一个函数将它的执行完成情况通过
返回值传上来就OK了(象众多的WINAPI函数一样),干嘛还引入这个异常机制呢?
当时的异常的使用也仅仅限于文件的读写,数据库的提交等。事实上,等我开始用JAVA时,
因为强制使用异常,才体会到异常的用处。
使用异常或使用函数返回值来表示函数的完成情况又是面向对象和面向过程的区别之一。
使用异常的好处,就是被调函数执行出了一点问题时,只管抛出相应异常,不关心谁来处理,
如何处理这个异常;而函数的调用者,扑捉到执行用的异常时,自己如果能处理,则处理,
将其消化,否则,继续把异常向上抛。
也是为了调试程序和程序交付后的维护的需要,我想让异常能具有下面的功能:
1.记录异常发生的时间;
2.记录最初抛出异常的类名及函数名,以及当时程序环境的描述(主要是象sql语句一样的敏感语句);
3.发生异常时的函数调用堆栈;
4.发生异常后,能将异常的详细信息(包括上面3点)记录DB或某个日志文件中,通过记录的日志,
我可以在系统交付后能跟踪程序执行的出错情况,能进行相应的错误修复。
不过,很遗憾,因为时间关系,功能4我并没有实现。
我把异常按严重级别分为几类,异常被扑获后,进行了响应的处理。
我最初的设计是写一个自定义的抽象异常类继承自Exception类,然后派生出每个“严重级别”
的异常类,其它实际的异常都从这里继承,做到象JAVA异常一样的见名知意。最后,考虑了一
下本系统规模和时间,就只写了一个类,“严重级别”就作为了这个类的一个成员变量。
程序实现大致如下
-----------------------------------------------------------------------------
type
TExceptLevel=(elMsg,elIgnore,elCanTry,elJustAlarm,elSerious);
TExceptionEx=class(Exception)
protected
FLevel: TExceptLevel;
FVendor: string;
FNum: string; //异常号 或 异常名
FInfo: string;
FTime: TDateTime;
FCallStacks: TStrings;
procedure SetInfo(const Value: string);
procedure SetLevel(const Value: TExceptLevel);
procedure SetNum(const Value: string);
procedure SetTime(const Value: TDateTime);
procedure SetVendor(const Value: string);
public
property Num:string read FNum write SetNum; //异常号 或 异常名
property Level:TExceptLevel read FLevel write SetLevel; //异常级别
property Vendor:string read FVendor write SetVendor; //异常产生者
property Time:TDateTime read FTime write SetTime; //产生异常的时间
property Info:string read FInfo write SetInfo; //异常信息
property CallStacks:TStrings read FCallStacks ; //异常处代码的详细信息,以及调用路径
public
Constructor Create(Aex:Exception;ANum:string;ALevel:TExceptLevel;AVendor:string;Ainfo:string;ACallStack:string);
Destructor Destroy();override;
procedure AddCallStacks(funInfo:string); virtual;
end;
implementation
procedure TExceptionEx.AddCallStacks(funInfo: string);
begin
Self.FCallStacks.Add(funInfo);
end;
constructor TExceptionEx.Create(Aex: Exception; ANum: string;ALevel: TExceptLevel; AVendor, Ainfo, ACallStack: string);
begin
Self.HelpContext:=Aex.HelpContext;
Self.Message:=Aex.Message;
Self.FNum:=ANum;
Self.FLevel:=ALevel;
Self.FVendor:=AVendor;
if Ainfo='' then Self.FInfo:=Aex.Message
else Self.FInfo:=Ainfo;
Self.FTime:=Now;
Self.FCallStacks:=TStringList.Create();
Self.FCallStacks.Clear();
Self.FCallStacks.Add(ACallStack);
//TODO:可在此出将异常记录到日志文件中
end;
destructor TExceptionEx.Destroy;
begin
FreeAndNil(FCallStacks);
inherited;
end;
...
-----------------------------------------------------------------------
几乎在所有可能出现异常的代码中,都加上异常不扑获代码
try
{some codes}
except
on ex:TExceptionEx do begin
ex.AddCallStacks('TAcHouse.SelectHouseMeter()'); //填加调用函数名称
raise ;
end;
on ex:Exception do begin
raise TExceptionEx.Create(ex,'ex_unknown',elSerious,'TacHouse.SelectHouseMeter','无法得到码表信息','TacHouse.SelectHouseMeter()');
end;
end;
在最顶的界面层,根据情况显示异常
try
{some codes}
except
on ex:TExceptionEx do begin
TPM.GetSelf().ShowMessage(ex);
end;
end;
//ShowMessage是自定义的对话框,可以显示我的异常,用户一般只看到简单的提示信息,通过点击
“详细”按钮,能看到异常的所有详细信息。
现在看来,这个类写的有点罗嗦,有些地方应该简化一些。
(未完)
最初接触Exception也是在Delphi中,那时很不明白,一个函数将它的执行完成情况通过
返回值传上来就OK了(象众多的WINAPI函数一样),干嘛还引入这个异常机制呢?
当时的异常的使用也仅仅限于文件的读写,数据库的提交等。事实上,等我开始用JAVA时,
因为强制使用异常,才体会到异常的用处。
使用异常或使用函数返回值来表示函数的完成情况又是面向对象和面向过程的区别之一。
使用异常的好处,就是被调函数执行出了一点问题时,只管抛出相应异常,不关心谁来处理,
如何处理这个异常;而函数的调用者,扑捉到执行用的异常时,自己如果能处理,则处理,
将其消化,否则,继续把异常向上抛。
也是为了调试程序和程序交付后的维护的需要,我想让异常能具有下面的功能:
1.记录异常发生的时间;
2.记录最初抛出异常的类名及函数名,以及当时程序环境的描述(主要是象sql语句一样的敏感语句);
3.发生异常时的函数调用堆栈;
4.发生异常后,能将异常的详细信息(包括上面3点)记录DB或某个日志文件中,通过记录的日志,
我可以在系统交付后能跟踪程序执行的出错情况,能进行相应的错误修复。
不过,很遗憾,因为时间关系,功能4我并没有实现。
我把异常按严重级别分为几类,异常被扑获后,进行了响应的处理。
我最初的设计是写一个自定义的抽象异常类继承自Exception类,然后派生出每个“严重级别”
的异常类,其它实际的异常都从这里继承,做到象JAVA异常一样的见名知意。最后,考虑了一
下本系统规模和时间,就只写了一个类,“严重级别”就作为了这个类的一个成员变量。
程序实现大致如下
-----------------------------------------------------------------------------
type
TExceptLevel=(elMsg,elIgnore,elCanTry,elJustAlarm,elSerious);
TExceptionEx=class(Exception)
protected
FLevel: TExceptLevel;
FVendor: string;
FNum: string; //异常号 或 异常名
FInfo: string;
FTime: TDateTime;
FCallStacks: TStrings;
procedure SetInfo(const Value: string);
procedure SetLevel(const Value: TExceptLevel);
procedure SetNum(const Value: string);
procedure SetTime(const Value: TDateTime);
procedure SetVendor(const Value: string);
public
property Num:string read FNum write SetNum; //异常号 或 异常名
property Level:TExceptLevel read FLevel write SetLevel; //异常级别
property Vendor:string read FVendor write SetVendor; //异常产生者
property Time:TDateTime read FTime write SetTime; //产生异常的时间
property Info:string read FInfo write SetInfo; //异常信息
property CallStacks:TStrings read FCallStacks ; //异常处代码的详细信息,以及调用路径
public
Constructor Create(Aex:Exception;ANum:string;ALevel:TExceptLevel;AVendor:string;Ainfo:string;ACallStack:string);
Destructor Destroy();override;
procedure AddCallStacks(funInfo:string); virtual;
end;
implementation
procedure TExceptionEx.AddCallStacks(funInfo: string);
begin
Self.FCallStacks.Add(funInfo);
end;
constructor TExceptionEx.Create(Aex: Exception; ANum: string;ALevel: TExceptLevel; AVendor, Ainfo, ACallStack: string);
begin
Self.HelpContext:=Aex.HelpContext;
Self.Message:=Aex.Message;
Self.FNum:=ANum;
Self.FLevel:=ALevel;
Self.FVendor:=AVendor;
if Ainfo='' then Self.FInfo:=Aex.Message
else Self.FInfo:=Ainfo;
Self.FTime:=Now;
Self.FCallStacks:=TStringList.Create();
Self.FCallStacks.Clear();
Self.FCallStacks.Add(ACallStack);
//TODO:可在此出将异常记录到日志文件中
end;
destructor TExceptionEx.Destroy;
begin
FreeAndNil(FCallStacks);
inherited;
end;
...
-----------------------------------------------------------------------
几乎在所有可能出现异常的代码中,都加上异常不扑获代码
try
{some codes}
except
on ex:TExceptionEx do begin
ex.AddCallStacks('TAcHouse.SelectHouseMeter()'); //填加调用函数名称
raise ;
end;
on ex:Exception do begin
raise TExceptionEx.Create(ex,'ex_unknown',elSerious,'TacHouse.SelectHouseMeter','无法得到码表信息','TacHouse.SelectHouseMeter()');
end;
end;
在最顶的界面层,根据情况显示异常
try
{some codes}
except
on ex:TExceptionEx do begin
TPM.GetSelf().ShowMessage(ex);
end;
end;
//ShowMessage是自定义的对话框,可以显示我的异常,用户一般只看到简单的提示信息,通过点击
“详细”按钮,能看到异常的所有详细信息。
现在看来,这个类写的有点罗嗦,有些地方应该简化一些。
(未完)