简体   繁体   English

尝试/例外/最终在Delphi XE中无法正常工作

[英]Try/Except/Finally not working properly in Delphi XE

I'm having this funny issue with Delphi XE where I create a try/except/finally statement and when the application generate an exception the except block is never called it jump straight to the finally block, I tried few things like invert the try/except/finally to try/finally/except, try to change the try blocks to different places, clean the code and recompile in case was a Delphi issue but noting seems to work. 我在Delphi XE上遇到了一个有趣的问题,我在其中创建了try / except / finally语句,当应用程序生成异常时,永远不会调用except块,它会直接跳转到finally块,我尝试了一些尝试,例如反转try /除了/最终尝试/最终/例外,尝试将try块更改为不同的位置,清理代码并重新编译,以防出现Delphi问题,但请注意似乎可行。

What I'm trying to accomplish here is to show a dialog message to the user and after clean up the code in case of a crash. 我要在此处完成的工作是向用户显示对话框消息,并在清理代码后以防崩溃。

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

If an exception is raised inside the try/except, and not handled by code further down the call stack, it will be caught by your exception handler. 如果在try / except内引发了异常,并且未在调用堆栈之后的代码中进行处理,则异常处理程序将捕获该异常。

You are claiming the ExportGridToXXX is raising an exception that is not caught by the exception handler in your code. 您声称ExportGridToXXX引发了代码中的异常处理程序未捕获的异常。 But that claim cannot be true. 但是这种说法是不正确的。 Either no exception is raised, or ExportGridToXXX already handles the exception. 没有引发异常,或者ExportGridToXXX已处理该异常。

On the more general subject of exception handling, the general policy should be not to handle them if at all possible. 在更一般的异常处理主题上,一般策略应尽可能不处理它们。 You should only handle them in case you need to stop the exception propagating, and need to deal with the exception at this point in the code. 仅应在需要停止传播异常的情况下处理它们,并且此时需要在代码中处理异常。 Normally, particularly in a UI program, you would simply let the exception be handled by the top-level exception handler. 通常,特别是在UI程序中,只需让顶级异常处理程序处理该异常即可。

As well as that point, you code swallows all exceptions, irrespective of their type. 到那时,您的代码将吞噬所有异常,无论它们的类型如何。 That's bad practice. 那是不好的做法。 Supposing that you do want to handle exceptions raised by ExportGridToXXX , you should only handle the exception classes that are expected. 假设您确实想处理ExportGridToXXX引发的ExportGridToXXX ,则应该只处理预期的异常类。 For instance, you might encounter EAccessViolation for which your app's policy is to terminate. 例如,您可能会遇到EAccessViolation ,您的应用程序策略将为此终止。 But since you swallowed it, treating it in the same handler used to trap sharing violations, you cannot apply that policy. 但是由于吞下了它,并在与捕获共享冲突相同的处理程序中对其进行了处理,因此您无法应用该策略。 Always be discerning in your handling of exceptions. 在处理异常时要始终保持敏锐。

Do the Export(smth) functions reside in a separate DLL? Export(smth)函数是否驻留在单独的DLL中? Then your application's Exception class is not the same as external DLL's Exception class. 然后,您的应用程序的Exception类与外部DLL的Exception类不同。

Your exception handler is swallowing the exception, try re-raising instead: 您的异常处理程序吞下了异常,请尝试重新引发:

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM