我使用一个函数将应用程序错误记录到一个文件中。我在我的主窗体上有它。如果出现错误,如何使用此函数告诉我的其他表单?我偶然将其添加到我的查询中以其他形式:
......
try
ClientDataSet1.Execute;
ClientDataSet1.Close;
except
on E:Exception do begin
ShowMessage('Error : ' + E.Message);
LogError(E);
....
我的LogError(E);无法识别(给出错误)。尝试添加函数:procedure LogError(E:Exception);公共用途,但不会工作。
答案 0 :(得分:2)
虽然Delphi是面向对象的语言,但它也可以处理非OO实体。
想想,你的主要形式是哪种形式的财产?
答案是主要形式不是任何其他形式的属性,它是一个全局对象。关于你的功能应该完全相同。
unit Main;
interface uses .......;
type TMainForm = class (TForm)....
....
end;
Procedure LogError(const message: string);
implementation uses .....;
Procedure LogError(const message: string);
begin
...
end;
(**********)
procedure TMainForm.FormCreate(...);
begin
....
end;
...
end.
现在更好的选择是将LogError从任何形式完全解耦。
Unit MyLogger;
interface uses ....; // but does not uses Main or any other form
procedure SetupLog(....);
// to initialize it and change any settings you may wish
// maybe you would choose to save messages to file
// or use Windows debug interface - OutputDebugString
// or to a network SysLog server
// or just WriteLn it to a text window
// or to some TMemo in a graphic window
// or to file AND to a memo - that also might make sense.
// just keep it extensible
Procedure LogWarning(const message: string);
Procedure LogError(const message: string);
implementation uses ...;
function GenericLoggingSink(.....);
begin
...
end;
Procedure LogError(const message: string);
begin
GenericLoggingSink( Log_Message_Type_Error, message, ... );
end;
Procedure LogWarning(const message: string);
begin
GenericLoggingSink( Log_Message_Type_Warning, message, ... );
end;
您的主表单应该使用此单元和此功能与您的应用程序中的所有其他表单相同的条款。
作为第三部分,我建议您根据日志记录程序考虑您的需求。 实际上这样做只对非常简单的日志记录需求有意义。非常简单。
否则只需采用任何现有的Delphi日志框架并利用其中实现的大量功能。例如,您可以只记录您要编写的任何类的对象吗?
创建自己的日志库的唯一原因是“我的程序非常简单,它只需要最原始的日志记录。即兴创建我自己的系统比复制粘贴库初始化和设置更快现成的库的例子“。
Log4Delphi和Log4D是众所周知的FLOSS库,尽管它们看起来有点遗弃。也许没有什么可以延长的。这些是最旧的,但也有一些较新的FLOSS库,一个简单的例子是http://blog.synopse.info/post/2013/02/03/Log-to-the-console
如果有的话,你可以阅读他们的文本并从中学习。
还有像Is there a way to do normal logging with EureakLog?中列出的那些商业库,Delphi本身附带了限量版的CodeSite日志框架。
像CnWizards和GExperts这样的Delphi IDE增强功能也带有简化的面向调试的日志记录界面。
如果你敢的话,谷歌会为你带来更多选择: - )答案 1 :(得分:2)
我想指出,您的异常处理方法非常繁琐且编码浪费。更不用说非常危险了。当有更实用的方法时,您不希望使用各个处理程序乱丢代码来记录异常。
幸运的是,德尔福提供了使这更容易的方法。首先是关于结构化异常处理的一些小背景......大多数开发人员都错误地尝试通过编写如下代码来处理错误:
try
//Do Something
except
//Show Error
//Log Error
end;
上述代码的问题在于 吞下 错误。即使用户看到错误消息,错误本身也会从程序的其余部分隐藏。这会导致程序的其他部分因为错误而执行不应该的事情。
想象一个调用以下例程的程序:LoadAccount; ApplyDiscount; ProcessPayment;
。但是第一个例程引发了一个错误。程序员(错误地认为他们正在勤奋)决定如上所述“处理”。 问题,接下来的两个例程仍将被称为 ,好像 没有错!这可能意味着对 错误的 帐户应用折扣并进行付款处理!
重点是结构化异常处理使我们免于这些麻烦(前提是我们没有打破它的工作方式)。如果LoadAccount
例程没有尝试“处理”异常,那么当应用程序处于“异常状态”时,代码只会继续跳出例程直到找到最终 / 除了处理程序。
这非常适合事件驱动程序 假设用户单击一个按钮,该按钮将导致程序启动多步骤任务:使用循环,调用子方法,创建对象等。如果 任何 出错,你想放弃整个任务并等待下一个输入。你不想顽固地继续努力完成任务;因为你要么只是得到更多的错误,要么更糟:后来的改变会做错事,因为之前的必要步骤没有成功完成。
如前所述,如果 只是单独留下一个例外 ,则错误将“冒泡”到外部异常处理程序。在标准的GUI应用程序中,这将是默认的Application
异常处理程序。
实际上在这个阶段,没有什么特别之处:如果在前面描述的按钮点击任务中间引发了异常,则默认异常处理程序 将 显示向用户发送错误消息。唯一缺少的是日志记录。幸运的是,Delphi使您可以轻松拦截默认的Application
异常处理程序。因此,您可以提供自己的实现,并根据需要记录错误。
您需要做的就是:
TExceptionEvent
签名编写方法
例如。 procedure MyHandleException(ASender: TObject; E: Exception);
。Application.OnException := MyHandleException;
当然,这仅涵盖异常的记录。如果要进行任何其他临时日志记录,则希望能够重用代码。这基本上要求您将日志记录代码移动到一个单独的单元中, all 可以根据需要调用其他单元。
所以把这些东西放在一起你可能会做如下事情:
TLogger = class
public
procedure WriteToLog(S: string); //Performs actual logging of given string
procedure HandleException(ASender: TObject; E: Exception); //Calls WriteToLog
end;
然后您可以在程序单元中进行设置,如下所示:
begin
Logger := TLogger.Create(...);
Application.OnException := Logger.HandleException;
Logger.WriteToLog('Custom exception handler has been assigned.');
//Rest of application startup code
end;
我提到如果发生意外异常,您要放弃当前任务。但是,如果您已经完成了一些因错误而应该 撤消 的事情会发生什么。然后你只需按如下方式实现它:
try
//Do something
except
//Undo
raise; //NOTE: more often than not, one should re-raise an
//exception so that callers are aware of the error.
end;
请注意, 此 是异常处理程序的主要用途。是的,他们也可以用来吞下例外。但是如果