我有这样的功能,我想重构
function Myfunction(sUrl, sFile: String) : Boolean;
var
GetData : TFileStream;
begin
Result := False;
//if the line below fails, I get an unhandled exception
GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
try
try
IdHTTP.Get(sUrl, GetData);
Result := (IdHTTP.ResponseCode = 200);
except
on E: Exception do begin
MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
end;
end;
finally
GetData.Free;
end;
end;
Procedure SomeOtherCode;
Begin
//How can I best defend against the unhandled exception above
//unless the call to the function is packed in a try .. except block
//the code jumps skips the if statement an goes to next
//exception block on the stack
if MyFunction('http://domain.com/file.html', 'c:\folder\file.html') then
ShowMessage('Got the file')
else
ShowMessage('Error !');
End
end;
问题:
请参阅上面的SomeOtherCode程序中的评论。
最好的问候
答案 0 :(得分:9)
将代码包装在try..except块中要捕获异常的位置:
function MyFunction(...): Boolean;
var
Stream: TFileStream;
begin
Result := False;
try
Stream := TFileStream.Create(...);
try
// more code
Result := ...
finally
Stream.Free;
end;
except
// handle exception
end
end;
答案 1 :(得分:3)
关于异常处理的重点是双重的:
finally
用于资源清理;你经常在商业逻辑中看到这一点except
用于对特定异常做出反应(并通过函数结果和中间变量去掉状态逻辑);你很难在商业逻辑中看到它在你的情况下:
Myfunction
不应返回布尔值,不包含except
块,也不应执行MessageBox
,只是让异常传播。
SomeOtherCode
应包含except
块,并告诉用户出现了什么问题。
示例:
procedure Myfunction(sUrl, sFile: String);
var
GetData: TFileStream;
begin
Result := False;
//if the line below fails, I get an unhandled exception
GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
try
IdHTTP.Get(sUrl, GetData);
if (IdHTTP.ResponseCode <> 200) <> then
raise Exception.CreateFmt('Download of %s failed, return code %d', [sURl, IdHTTP.ResponseCode]);
finally
GetData.Free;
end;
end;
procedure SomeOtherCode:
begin
try
MyFunction('http://domain.com/file.html', 'c:\folder\file.html');
except
on E: Exception do begin
MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
end;
end;
end;
现在代码更清晰了:
except
的地方cannot create file
,download failure
)祝你好运。
- 的Jeroen
答案 2 :(得分:2)
一种非常流行的解决方案是完全避免“成功”或“失败”返回值。而不是使用函数,而是使用过程并使用异常处理失败:
procedure Download(sUrl, sFile: String);
然后
try
Download ('http://domain.com/file.html', 'c:\folder\file.html');
ShowMessage('Got the file')
except
on E:Exxx do
begin
// handle exception
ShowMessage('Error !');
end
end;
这也会导致没有人可以调用该函数并静默忽略返回值。
答案 3 :(得分:1)
如果您希望您的函数向用户显示消息并在任何失败时返回false,请按如下方式对其进行编码:
function Myfunction(sUrl, sFile: String) : Boolean;
var
GetData : TFileStream;
begin
Result := False;
try
//if the line below fails, I get an unhandled exception
GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
try
try
IdHTTP.Get(sUrl, GetData);
Result := (IdHTTP.ResponseCode = 200);
except
on E: Exception do begin
MessageBox(0, PChar(E.message), 'Niðurhala skrá', MB_ICONERROR or MB_OK);
end;
end;
finally
GetData.Free;
end;
except
// you can handle specific exceptions (like file creation errors) or any exception here
end;
end;
警告强> 恕我直言,这种设计混合了业务逻辑(例如从Internet获取资源/文件并将其保存到文件中)和用户界面逻辑(例如在出现错误时向用户显示消息)。
通常,将业务与UI逻辑分离是一种更好的方法,因为您的代码是可重用的。
例如,您可能希望重新考虑因素:
function DownloadToAFile(const sUrl, sFile: string): boolean;
var
GetData : TFileStream;
begin
GetData := TFileStream.Create(sFile, fmOpenWrite or fmCreate);
try
IdHTTP.Get(sUrl, GetData);
Result := (IdHTTP.ResponseCode = 200);
finally
GetData.Free;
end;
end;
function UIDownloadToAFile(const sUrl, sFile: string): boolean;
begin
try
Result := DownloadToAFile(sURL, sFile);
except
on E: EIDException do //IndyError
MessageBox(0, PChar(E.message), 'Internet Error', MB_ICONERROR or MB_OK);
on E: EFileCreateError do //just can't remember the extact class name for this error
MessageBox(0, PChar(E.message), 'File create Error', MB_ICONERROR or MB_OK);
end;
end;
procedure SomeOtherCode:
begin
if UIDownloadToAFile('http://domain.com/file.html', 'c:\folder\file.html') then
ShowMessage('Got the file')
else
ShowMessage('Error !');
end;
明天,如果您正在编写服务或DataSnap模块,您可以自由使用DownloadToAFile,也可以编写新的ServiceDownloadToAFile,将错误写入日志或Windows事件,或者发送电子邮件通知HostAdmin。
答案 4 :(得分:0)
您应该只使用一个try
并获取所有功能代码。
答案 5 :(得分:0)
由于某些原因,大多数人滥用除了 - 最终组合。正确的顺序是
try
// allocate resource here
try
finally
// free resource here
end;
except
// handle exception here
end;
这使您可以捕获构造函数和析构函数中的异常。