
1. Delphi异常处理基础与核心机制Delphi的异常处理机制建立在Object Pascal语言强大的面向对象特性之上其核心是通过异常类体系来封装和处理程序运行时的各种错误情况。与C等语言的异常处理相比Delphi的实现更加简洁直观同时又不失灵活性。1.1 异常类继承体系Delphi中所有异常类的基类是Exception注意类名以E开头而非T开头定义在SysUtils单元中。这个基类提供了几个关键属性和方法Message属性存储异常的描述信息StackTrace记录异常发生时的调用堆栈需手动启用Create构造方法支持多种重载形式创建异常对象典型的异常类派生关系如下Exception ├── EAbort ├── EHeapException │ ├── EOutOfMemory │ └── EInvalidPointer ├── EInOutError ├── EExternal │ └── EExternalException └── 其他专用异常类1.2 基本异常处理结构Delphi提供了两种基础异常处理结构分别适用于不同场景try-except-end结构try // 可能抛出异常的代码 SomeRiskyOperation; except on E: EDivByZero do ShowMessage(除零错误: E.Message); on E: EAccessViolation do ShowMessage(内存访问错误: E.Message); else ShowMessage(未知错误发生); end;这种结构的特点是只有当异常发生时才会执行except块支持按异常类型精确捕获异常被捕获后默认会被处理掉除非重新raisetry-finally-end结构Resource : TResource.Create; try // 使用资源的代码 Resource.DoSomething; finally Resource.Free; // 无论是否发生异常都会执行 end;这种结构的关键特性finally块始终会执行无论是否发生异常不处理异常只是确保资源释放常用于文件、内存、锁等资源的清理重要提示不要混淆这两种结构的作用。如果需要同时处理异常和释放资源应该嵌套使用try Resource : TResource.Create; try // 使用资源 finally Resource.Free; end; except on E: Exception do // 异常处理 end;2. Delphi异常处理高级技巧2.1 自定义异常类创建自定义异常类可以更好地组织特定领域的错误处理type EMyBusinessError class(Exception) private FErrorCode: Integer; public constructor Create(const Msg: string; AErrorCode: Integer); property ErrorCode: Integer read FErrorCode; end; constructor EMyBusinessError.Create(const Msg: string; AErrorCode: Integer); begin inherited Create(Msg); FErrorCode : AErrorCode; end; // 使用示例 procedure DoBusinessLogic(Value: Integer); begin if Value 0 then raise EMyBusinessError.Create(无效的输入值, 1001); // 正常逻辑... end;自定义异常的最佳实践类名以E开头继承自Exception或其子类为特定领域或模块创建专门的异常类层次可以添加额外的属性和方法来携带更多错误信息在构造函数中提供有意义的默认消息2.2 异常链与嵌套异常Delphi支持异常嵌套处理这在复杂操作中特别有用procedure ProcessData; begin try // 主逻辑 except on E: EDataProcessingError do begin // 包装原始异常添加上下文信息 raise EAdvancedProcessingError.CreateFmt( 处理数据时出错附加信息: %s, [E.Message]); end; end; end;处理嵌套异常时的注意事项使用InnerException机制Delphi 2009避免过度包装导致原始错误信息丢失在日志中记录完整的异常链2.3 异常与资源管理正确的资源管理是健壮代码的关键。Delphi提供了几种模式接口自动管理procedure UseInterfaces; var List: IInterfaceList; begin List : TInterfaceList.Create; // 使用List... end; // 自动释放使用TDisposable模式Delphi 2010procedure UseDisposable; var Obj: TSomeDisposableObject; begin Obj : TSomeDisposableObject.Create; try // 使用Obj... finally Obj.DisposeOf; // 特殊情况下需要立即释放 end; end;记录类型辅助Delphi 10.4procedure UseManagedRecords; var Guard: TSomeGuard; begin Guard.Initialize; // 使用受保护的资源... end; // 自动调用Guard.Finalize3. Delphi运行时异常详解3.1 常见运行时异常类型Delphi运行时库定义了丰富的异常类型主要分为以下几类3.1.1 类型转换异常EConvertError字符串到数值转换失败EInvalidCast对象类型转换失败as操作符// 触发EConvertError的例子 var I: Integer; begin I : StrToInt(ABC); // 不是有效数字 end; // 触发EInvalidCast的例子 var Obj: TObject; Stream: TStream; begin Obj : TObject.Create; try Stream : Obj as TStream; // 类型不兼容 finally Obj.Free; end; end;3.1.2 数学运算异常EDivByZero除零错误ERangeError数值超出范围EIntOverflow整数溢出EMathError基础数学错误// 触发EDivByZero的例子 var A, B: Integer; begin A : 10; B : 0; A : A div B; // 除零 end; // 触发ERangeError的例子 var SmallNum: ShortInt; begin SmallNum : 200; // ShortInt范围是-128~127 end;3.1.3 文件与I/O异常EInOutError基础I/O错误EFileStreamError文件流操作错误EFCreateError文件创建失败EFOpenError文件打开失败// 触发EFOpenError的例子 var F: TextFile; begin AssignFile(F, 不存在的文件.txt); Reset(F); // 尝试打开不存在的文件 end;3.2 硬件与系统级异常这些异常通常表示更严重的问题EAccessViolation非法内存访问最常见的AV错误EStackOverflow栈溢出EControlC用户按下CtrlC中断EPrivilege特权指令错误处理这类异常时需要特别注意try // 可能触发硬件异常的代码 except on E: EAccessViolation do begin // 记录详细错误信息 LogAVError(E); // 通常无法恢复应终止操作 Abort; end; end;警告不要轻易捕获硬件异常除非你知道如何正确处理。不恰当的处理可能掩盖严重问题。4. 异常处理最佳实践4.1 异常处理策略防御性编程// 不好的做法依赖异常处理流程控制 try while True do ProcessNextItem; except on E: ENoMoreItems do ; // 正常结束 end; // 好的做法显式检查状态 while HasMoreItems do ProcessNextItem;异常粒度控制在模块边界处处理异常避免在内部循环中使用异常处理对可预见的错误使用错误码而非异常资源清理保证// 不安全的做法 try Obj1 : TObject1.Create; Obj2 : TObject2.Create; // 使用Obj1和Obj2 finally Obj1.Free; Obj2.Free; // 如果Obj1.Free抛出异常Obj2会泄漏 end; // 安全的做法 Obj1 : nil; Obj2 : nil; try Obj1 : TObject1.Create; try Obj2 : TObject2.Create; // 使用Obj1和Obj2 finally Obj2.Free; end; finally Obj1.Free; end;4.2 异常日志记录完善的日志记录对调试异常至关重要procedure LogException(E: Exception; const Context: string); var LogFile: TextFile; TimeStr: string; begin DateTimeToString(TimeStr, yyyy-mm-dd hh:nn:ss, Now); AssignFile(LogFile, error.log); try if FileExists(error.log) then Append(LogFile) else Rewrite(LogFile); Writeln(LogFile, [ TimeStr ] Context); Writeln(LogFile, Exception: E.ClassName); Writeln(LogFile, Message: E.Message); {$IFDEF DEBUG} Writeln(LogFile, Stack trace: GetStackTrace); {$ENDIF} finally CloseFile(LogFile); end; end;日志记录的最佳实践包含时间戳、异常类型和消息在调试版本中包含堆栈跟踪避免在日志记录过程中引发新异常考虑使用专业日志库如Log4D4.3 异常处理性能考量异常处理对性能的影响主要来自异常对象的构造和销毁堆栈展开过程异常处理块的查找优化建议避免在性能关键路径中使用异常重用异常对象谨慎使用使用Exit/Break/Continue代替异常进行流程控制对频繁发生的错误使用错误码而非异常性能测试示例procedure TestExceptionPerformance; var I: Integer; Start: Cardinal; begin // 测试异常路径 Start : GetTickCount; for I : 1 to 100000 do begin try raise ETestException.Create(Test); except end; end; Writeln(异常路径: , GetTickCount - Start, ms); // 测试正常路径 Start : GetTickCount; for I : 1 to 100000 do begin if False then raise ETestException.Create(Test); end; Writeln(正常路径: , GetTickCount - Start, ms); end;5. 常见问题与解决方案5.1 异常处理常见陷阱过度使用异常// 不好的做法用异常处理正常逻辑 try Result : StrToInt(Input); except Result : 0; // 默认值 end; // 更好的做法使用TryStrToInt if not TryStrToInt(Input, Result) then Result : 0;异常信息不足// 不好的做法模糊的错误信息 raise Exception.Create(发生错误); // 好的做法提供详细上下文信息 raise Exception.CreateFmt(处理文件%s时出错行号%d, [FileName, LineNo]);资源泄漏// 有泄漏风险的代码 try Obj : TMyObject.Create; Obj.DoSomethingRisky; Obj.Free; except // 如果DoSomethingRisky抛出异常Obj不会被释放 end;5.2 调试异常技巧在IDE中配置异常调试打开Debugger Options在Language Exceptions中添加需要中断的异常类型设置First chance exceptions处理方式使用MadExcept或JCLDebug等工具获取完整堆栈uses JclDebug; procedure InitDebugInfo; begin JclStartExceptionTracking; // 现在所有异常都会记录完整调用堆栈 end;条件断点技巧在异常发生前设置断点右键点击断点 - Condition输入条件如ExceptionClass nil5.3 跨平台异常处理在FireMonkey跨平台应用中需注意平台特定异常try // 跨平台代码 except on E: Exception do begin {$IFDEF IOS} HandleIOSException(E); {$ENDIF} {$IFDEF ANDROID} HandleAndroidException(E); {$ENDIF} end; end;异步异常处理// 处理异步任务中的异常 AsyncTask.Run( procedure begin try // 后台操作 except on E: Exception do begin TThread.Synchronize(nil, procedure begin HandleExceptionInMainThread(E); end); end; end; end);移动平台特殊考虑内存不足异常更常见需要处理应用被中断的情况异常信息可能需要显示为Toast或Alert6. 实际案例解析6.1 文件处理中的异常处理完整的安全文件操作模板procedure SafeFileCopy(const Source, Dest: string); var SourceStream, DestStream: TFileStream; begin SourceStream : nil; DestStream : nil; try try SourceStream : TFileStream.Create(Source, fmOpenRead or fmShareDenyWrite); DestStream : TFileStream.Create(Dest, fmCreate or fmShareExclusive); if DestStream.CopyFrom(SourceStream, SourceStream.Size) SourceStream.Size then raise EFileStreamError.Create(文件复制不完整); except on E: EInOutError do begin // 根据错误代码提供更友好的消息 case E.ErrorCode of 2: raise EFileNotFoundException.Create(源文件不存在); 5: raise EAccessDeniedException.Create(目标文件访问被拒绝); 32: raise ESharingViolation.Create(文件被其他进程锁定); else raise; end; end; on E: EStreamError do begin // 添加操作上下文信息 raise EFileOperationException.CreateFmt( 文件操作%s到%s失败: %s, [Source, Dest, E.Message]); end; end; finally SourceStream.Free; DestStream.Free; end; end;6.2 数据库操作异常处理数据库应用中的典型异常处理模式procedure UpdateCustomerBalance(CustomerID: Integer; Delta: Currency); var Conn: TSQLConnection; Qry: TSQLQuery; begin Conn : nil; Qry : nil; try Conn : TSQLConnection.Create(nil); SetupConnection(Conn); // 配置连接参数 Qry : TSQLQuery.Create(nil); Qry.SQLConnection : Conn; try Conn.Open; Qry.SQL.Text : UPDATE Customers SET Balance Balance :Delta WHERE ID :ID; Qry.ParamByName(Delta).AsCurrency : Delta; Qry.ParamByName(ID).AsInteger : CustomerID; Qry.ExecSQL; if Qry.RowsAffected 0 then raise EDatabaseError.Create(客户记录不存在); except on E: ESQLDatabaseError do begin // 处理特定SQL错误 if Pos(FK_Customer_Order, E.Message) 0 then raise EBusinessRuleException.Create(不能删除有订单的客户) else if E.ErrorCode 2627 then // 主键冲突 raise EDuplicateRecordException.Create(记录已存在) else raise; // 重新抛出未处理的异常 end; on E: Exception do begin // 记录原始异常并包装 LogException(E, UpdateCustomerBalance); raise EDatabaseOperationException.Create(更新客户余额失败); end; end; finally Qry.Free; Conn.Free; end; end;6.3 多线程环境异常处理线程安全异常处理示例type TWorkerThread class(TThread) private FError: Exception; FOnError: TNotifyEvent; protected procedure Execute; override; procedure HandleError; procedure DoTerminate; override; public property OnError: TNotifyEvent read FOnError write FOnError; end; procedure TWorkerThread.Execute; begin try // 线程主工作代码 DoSomeWork; except on E: Exception do begin FError : AcquireExceptionObject as Exception; Synchronize(HandleError); end; end; end; procedure TWorkerThread.HandleError; begin if Assigned(FOnError) then FOnError(Self); end; procedure TWorkerThread.DoTerminate; begin FreeAndNil(FError); inherited; end; // 使用示例 procedure TMainForm.StartWorker; var Worker: TWorkerThread; begin Worker : TWorkerThread.Create(True); Worker.FreeOnTerminate : True; Worker.OnError : HandleWorkerError; Worker.Start; end; procedure TMainForm.HandleWorkerError(Sender: TObject); var Worker: TWorkerThread; begin Worker : Sender as TWorkerThread; ShowMessage(工作线程出错: Worker.FError.Message); end;7. 异常处理的高级话题7.1 异常与程序架构良好的异常处理策略应该与程序架构紧密结合分层架构中的异常处理数据访问层捕获原始数据库/文件异常转换为领域异常业务逻辑层处理领域异常可能转换为应用异常表示层捕获应用异常显示友好消息领域驱动设计中的异常使用领域特定异常类异常是领域模型的一部分通过异常显式表达业务规则违反事件驱动架构中的异常使用事件表示错误而非异常错误事件处理器统一处理支持异步错误通知7.2 异常安全保证级别借鉴C的概念Delphi代码也可以分为不同异常安全级别基本保证发生异常时不会泄漏资源强保证操作要么完全成功要么状态回滚不抛出保证操作保证不会抛出异常实现强保证的示例procedure TransferFunds(Source, Dest: TAccount; Amount: Currency); var OldSourceBalance, OldDestBalance: Currency; begin OldSourceBalance : Source.Balance; OldDestBalance : Dest.Balance; try Source.Withdraw(Amount); // 可能抛出异常 Dest.Deposit(Amount); // 可能抛出异常 except // 发生异常时回滚 Source.Balance : OldSourceBalance; Dest.Balance : OldDestBalance; raise; // 重新抛出异常 end; end;7.3 异常处理与设计模式模板方法模式type TAlgorithmTemplate class protected procedure Step1; virtual; abstract; procedure Step2; virtual; abstract; procedure HandleStep2Error(E: Exception); virtual; public procedure Execute; end; procedure TAlgorithmTemplate.Execute; begin Step1; try Step2; except on E: Exception do HandleStep2Error(E); end; end;责任链模式type IExceptionHandler interface function HandleException(E: Exception): Boolean; end; TExceptionHandlerChain class private FHandlers: TListIExceptionHandler; public procedure AddHandler(Handler: IExceptionHandler); function ProcessException(E: Exception): Boolean; end; function TExceptionHandlerChain.ProcessException(E: Exception): Boolean; var Handler: IExceptionHandler; begin for Handler in FHandlers do if Handler.HandleException(E) then Exit(True); Result : False; end;空对象模式type ILogger interface procedure LogException(E: Exception); end; TNullLogger class(TInterfacedObject, ILogger) procedure LogException(E: Exception); end; procedure TNullLogger.LogException(E: Exception); begin // 什么也不做 end;8. Delphi异常处理的最新发展8.1 现代Delphi版本的改进异常链支持Delphi 2009try // 可能抛出异常的代码 except on E: EOriginalException do raise EWrapperException.Create(上下文信息).At(E); end;异步异常支持Delphi XE7TTask.Run( procedure begin try // 后台任务 except on E: Exception do TThread.Queue(nil, procedure begin HandleExceptionInMainThread(E); end); end; end);平台特定异常增强iOS/Android特定异常类跨平台异常处理辅助函数8.2 第三方异常处理库MadExcept详细的崩溃报告堆栈跟踪异常截图用户反馈集成JCL Debug异常堆栈跟踪内存泄漏检测调试信息生成EurekaLog应用程序错误跟踪详细的错误报告与问题跟踪系统集成8.3 未来发展趋势更强大的异常诊断工具与IDE更深入的集成云错误报告服务AI辅助异常分析9. 异常处理单元测试9.1 测试异常抛出使用DUnitX测试框架的异常测试procedure TestTCalculator.TestDivideByZero; begin // 测试是否抛出预期的异常 Assert.WillRaise( procedure begin FCalculator.Divide(10, 0); end, EDivByZero); end; procedure TestTFileUtils.TestFileNotFound; begin // 测试异常消息内容 Assert.WillRaiseWithMessage( procedure begin TFileUtils.LoadFile(不存在的文件.txt); end, EFileNotFoundException, 文件未找到); end;9.2 测试异常处理验证异常处理逻辑的正确性procedure TestTErrorHandler.TestHandleDatabaseError; var Handler: TErrorHandler; Result: Boolean; begin Handler : TErrorHandler.Create; try // 测试处理特定错误码 Result : Handler.HandleError(EDatabaseError.Create(超时)); Assert.IsTrue(Result, 应处理数据库超时错误); // 测试忽略无关异常 Result : Handler.HandleError(EInvalidOp.Create(无效操作)); Assert.IsFalse(Result, 不应处理无效操作异常); finally Handler.Free; end; end;9.3 集成测试中的异常模拟异常场景进行端到端测试procedure TestTOrderService.TestPlaceOrderWithInvalidItem; var Service: TOrderService; Order: TOrder; begin Service : TOrderService.Create; try Order : TOrder.Create; try Order.AddItem(-1); // 无效商品ID // 验证是否抛出正确的业务异常 Assert.WillRaise( procedure begin Service.PlaceOrder(Order); end, EOrderValidationException); finally Order.Free; end; finally Service.Free; end; end;10. 异常处理在大型项目中的应用10.1 异常处理策略制定大型项目需要统一的异常处理策略异常分类标准技术性异常数据库、网络等业务规则异常用户输入验证异常系统级严重异常异常处理规范各层允许抛出的异常类型异常消息格式标准异常日志记录要求用户界面错误显示规范异常处理基础设施集中式异常处理器异常监控系统错误报告机制10.2 异常处理框架设计典型的企业级异常处理框架type IApplicationExceptionHandler interface procedure HandleException(E: Exception; const Context: string); end; TCompositeExceptionHandler class(TInterfacedObject, IApplicationExceptionHandler) private FHandlers: TListIApplicationExceptionHandler; public procedure AddHandler(Handler: IApplicationExceptionHandler); procedure HandleException(E: Exception; const Context: string); end; TLoggingExceptionHandler class(TInterfacedObject, IApplicationExceptionHandler) procedure HandleException(E: Exception; const Context: string); end; TUserNotificationHandler class(TInterfacedObject, IApplicationExceptionHandler) procedure HandleException(E: Exception; const Context: string); end; TErrorReportingHandler class(TInterfacedObject, IApplicationExceptionHandler) procedure HandleException(E: Exception; const Context: string); end; // 初始化框架 procedure InitializeExceptionHandling; var CompositeHandler: TCompositeExceptionHandler; begin GlobalExceptionHandler : TCompositeExceptionHandler.Create; CompositeHandler : GlobalExceptionHandler as TCompositeExceptionHandler; CompositeHandler.AddHandler(TLoggingExceptionHandler.Create); CompositeHandler.AddHandler(TUserNotificationHandler.Create); CompositeHandler.AddHandler(TErrorReportingHandler.Create); // 设置全局异常钩子 Application.OnException : GlobalExceptionHandler.HandleException; end;10.3 异常处理与团队协作代码审查要点资源释放是否正确异常消息是否有用是否过度捕获异常异常处理是否符合项目规范文档记录要求每个方法可能抛出的异常类型异常的业务含义推荐的异常处理方式知识共享机制异常处理模式库常见错误解决方案异常案例分析11. 异常处理性能优化11.1 异常处理开销分析异常处理的主要性能开销来源异常对象构造开销堆内存分配调用堆栈收集消息字符串处理异常处理机制开销查找异常处理块堆栈展开资源清理上下文切换开销正常执行流中断缓存局部性破坏11.2 性能优化技巧重用异常对象var ECustomError: ECustomException; initialization ECustomError : ECustomException.Create(自定义错误); finalization ECustomError.Free;避免深层调用堆栈扁平化调用层次减少try-except块嵌套使用快速异常type EFastException class(Exception) constructor Create; reintroduce; end; constructor EFastException.Create; begin inherited Create(快速异常); // 跳过堆栈收集等耗时操作 end;11.3 性能测试方法基准测试框架procedure BenchmarkException; var I: Integer; Stopwatch: TStopwatch; Elapsed: Int64; begin Stopwatch : TStopwatch.StartNew; for I : 1 to 100000 do begin try raise ETestException.Create(测试异常); except end; end; Elapsed : Stopwatch.ElapsedMilliseconds; Writeln(Format(异常处理耗时: %d ms, [Elapsed])); end;性能分析工具AQTimeSampling Profiler自定义性能计数器优化效果验证对比优化前后性能数据确保优化不破坏正确性监控生产环境性能12. 异常处理与程序健壮性12.1 防御性编程技巧输入验证procedure ProcessInput(const Input: string); begin if Input then raise EInvalidInputException.Create(输入不能为空); if not TRegEx.IsMatch(Input, ^[a-zA-Z0-9]$) then raise EInvalidInputException.Create(输入包含非法字符); // 处理有效输入 end;状态检查procedure TConnection.SendData(Data: TBytes); begin if not Connected then raise EConnectionStateException.Create(连接未建立); if Length(Data) 0 then raise EInvalidDataException.Create(数据不能为空); // 发送数据 end;不变式维护procedure TAccount.Withdraw(Amount: Currency); begin if Amount 0 then raise EInvalidAmountException.Create(金额必须大于零); if Amount FBalance then raise EInsufficientFundsException.Create(余额不足); FBalance : FBalance - Amount; // 检查不变式 Assert(FBalance 0, 余额不能为负); end;12.2 容错设计模式重试模式function RetryOperationT(Func: TFuncT; MaxAttempts: Integer): T; var Attempt: Integer; LastError: Exception; begin Attempt : 0; repeat Inc(Attempt); try Result : Func; Exit; except on E: ERetryableError do begin LastError : E; if Attempt MaxAttempts then Sleep(100 * Attempt); end; else raise; end; until Attempt MaxAttempts; raise LastError; end;熔断器模式type TCircuitBreaker class private FState: (cbClosed, cbOpen, cbHalfOpen); FFailureCount: Integer; FLastFailureTime: TDateTime; public function Execute(Action: TProc): Boolean; end; function TCiruitBreaker.Execute(Action: TProc): Boolean; begin case FState of cbClosed: try Action; Result : True; except on E: Exception do begin Inc(FFailureCount); if FFailureCount MaxFailures then begin FState : cbOpen; FLastFailureTime : Now; end; raise; end; end; cbOpen: if Now FLastFailureTime Timeout then FState : cbHalfOpen else raise ECircuitOpenException.Create(熔断器已打开); cbHalfOpen: try Action; FState : cbClosed; FFailureCount : 0; Result : True; except FState : cbOpen; FLastFailureTime : Now; raise; end; end; end;后备模式function GetDataWithFallback: TData; begin try Result : PrimaryDataSource.GetData; except on E: EDataSourceException do begin LogWarning(主数据源失败使用备用数据源: E.Message); try Result : SecondaryDataSource.GetData; except on E: EDataSourceException do begin LogError(所有数据源均失败: E.Message); raise EAllDataSourcesFailed.Create(无法获取数据); end; end; end; end; end;12.3 监控与警报异常监控系统设计type TExceptionMonitor class private FErrorCounts: TDictionarystring, Integer; FLastAlertTime: TDateTime; public procedure TrackException(E: Exception); procedure CheckAlertConditions; end; procedure TExceptionMonitor.TrackException(E: Exception); var Key: string; Count: Integer; begin Key : E.ClassName; if not FErrorCounts.TryGetValue(Key, Count) then Count : 0; FErrorCounts[Key] : Count 1; if (Count 1) AlertThreshold then CheckAlertConditions; end;异常趋势分析异常频率监控异常类型分布异常关联分析智能警报策略基于异常模式基于业务影响自适应阈值13. 异常处理与用户体验13.1 用户友好的错误信息错误消息设计原则明确说明问题提供解决方案避免技术术语保持积极语气多语言支持resourcestring SInvalidDate 日期无效请输入格式为YYYY-MM-DD的日期; SConnectionFailed 无法连接到服务器请检查网络设置; procedure ValidateDate(const DateStr: string); begin if not IsValidDate(DateStr) then raise EUserException.Create(SInvalidDate); end;上下文增强raise EUserException.CreateFmt( 无法保存%s文件到%s文件夹。请检查磁盘空间或权限。, [FileName, Directory]);13.2 错误恢复策略自动恢复尝试procedure SaveDocumentWithRetry(Doc: TDocument); var Attempts: Integer; begin Attempts : 0; repeat try Doc.Save; Exit; except on E: EFileAccessError do begin Inc(Attempts); if Attempts MaxAttempts then raise; case E.ErrorCode of ERROR_DISK_FULL: if TryFreeDiskSpace then Continue; ERROR_SHARING_VIOLATION: Sleep(1000