Try/Except/Finally无法在Delphi XE中正常工作

Try/Except/Finally无法在Delphi XE中正常工作,delphi,exception-handling,try-catch,delphi-xe,Delphi,Exception Handling,Try Catch,Delphi Xe,我在Delphi XE中遇到了一个有趣的问题,我创建了一个try/except/finally语句,当应用程序生成一个异常时,except块从未被调用,它直接跳到finally块,我尝试了一些事情,比如反转try/except/finally来try/finally/except,尝试将try块更改到不同的位置,清理代码并重新编译,以防出现Delphi问题,但似乎没有任何效果 我试图在这里完成的是向用户显示一条对话框消息,并在崩溃时清理代码 procedure CallbackExport(Se

我在Delphi XE中遇到了一个有趣的问题,我创建了一个try/except/finally语句,当应用程序生成一个异常时,except块从未被调用,它直接跳到finally块,我尝试了一些事情,比如反转try/except/finally来try/finally/except,尝试将try块更改到不同的位置,清理代码并重新编译,以防出现Delphi问题,但似乎没有任何效果

我试图在这里完成的是向用户显示一条对话框消息,并在崩溃时清理代码

procedure CallbackExport(Sender: TObject);
var
  SaveDlg: TSaveDialog;
  FileName: string;
begin
  SaveDlg := TSaveDialog.Create (nil);
  try
    try
      SaveDlg.Title := 'Export';
      SaveDlg.InitialDir := GetSystemPath(CSIDL_DESKTOP);
      SaveDlg.Options := [ofOverwritePrompt, ofEnableSizing];

      case (Sender as TMenuItem).Tag of
        cnExcel: begin
          SaveDlg.Filter := 'Excel File (*.xls)|*.xls';
        end;
        cnHtml: begin
          SaveDlg.Filter := 'HTML File (*.html)|*.html';
        end;
        cnTxt: begin
          SaveDlg.Filter := 'Text File (*.txt)|*.txt';
        end;
        cnCsv: begin
          SaveDlg.Filter := 'Comma Seperated File (*.csv)';
        end;
        cnXml: begin
          SaveDlg.Filter := 'XML file (*.xml)|*.xml';
        end;
      end;
      if not SaveDlg.Execute(self.Handle) then
        Exit;
      FileName := SaveDlg.FileName;

      case (Sender as TMenuItem).Tag of
        cnExcel: begin
          ExportGridToExcel(FileName, tvdGrid);
        end;
        cnHtml: begin
          ExportGridToHTML(FileName, tvdGrid);
        end;
        cnTxt: begin
          ExportGridToText(FileName, tvdGrid);
        end;
        cnCsv: begin
          ExportGridToText(FileName, tvdGrid, true, true, ',', '', '', 'CSV');
        end;
        cnXml: begin
          ExportGridToXML(FileName, tvdGrid);
        end;
      end;
    except
      on e: exception do
      begin
        ShowMessage('An error occurred while saving the file ' + FileName + #13#10 + 'With a message: ' + E.Message);
        StvdAudit.tvdAudit('Error saving file, reason: ' + E.Message);
      end;
    end;
  finally
    SaveDlg.Free;
  end;
end

如果在try/except中引发异常,而不是由调用堆栈下面的代码处理,则异常处理程序将捕获该异常

您声称ExportGridToXXX正在引发代码中异常处理程序未捕获的异常。但这种说法不可能是真的。未引发异常,或者ExportGridToXXX已处理该异常

关于异常处理这一更一般的主题,一般政策应该是尽可能不处理它们。您应该只在需要停止异常传播的情况下处理它们,并且需要在代码的这一点上处理异常。通常,特别是在UI程序中,您只需让顶级异常处理程序处理异常


除此之外,您的代码也会吞并所有异常,而不管它们的类型如何。那是个坏习惯。假设您确实希望处理ExportGridToXXX引发的异常,您应该只处理预期的异常类。例如,您可能会遇到应用程序策略终止的EAccessViolation。但是,由于您吞下了它,并在用于捕获共享冲突的同一处理程序中处理它,因此无法应用该策略。在处理异常时始终要有洞察力

Exportsmth函数是否驻留在单独的DLL中?然后,应用程序的异常类与外部DLL的异常类不同。

您的异常处理程序正在吞咽该异常,请尝试重新引发:

on e: exception do 
begin
  StvdAudit.tvdAudit('Error saving file, reason: ' + E.Message);
  raise exception.create('An error occurred while saving the file ' + FileName + #13#10 +       'With a message: ' + E.Message);
end;

这段代码看起来应该可以工作。你能提供一个我们可以实际编译和测试的可复制的例子吗?你怎么知道异常正在生成?尝试显式引发异常并查看发生了什么。提出例外。创建“这里有一个例外”;第二次尝试后,我同意。如图所示,这段代码中很少会引发异常。我猜ExportGrid函数可能正在吃掉/处理异常try。由于对这些函数的调用是try..finally块中的最后一个可执行行,因此它将显示为跳转到finally语句。要确认这一点,您只需在except子句之前添加一条ShowMessage,然后查看在IDE显示异常之后是否收到该消息。如果是这种情况,则不必在该函数内处理异常,也不必在except块just raise;上重新引发异常;。我不知道我是否说得很清楚……我从未使用过DevExpress,所以我不能真正断言任何东西,但我仍然猜测ExportGrid函数正在处理异常。我建议您设置一个断点,并在函数的DevExpress源代码[F7]中一直跟踪异常发生的位置和处理的位置。您应该有源代码,但可能不在避免重新编译的库路径中,这样可以节省时间。但是,当调试器请求.pas文件时,找到它并在调试器上进行选择,通常组件在其树中带有一个源目录。