The title says it, but here is an example:

try
  // ...
  raise EFileNotFoundException.Create('File not found!');
except
  on E: EFileNotFoundException do begin
    E.Message := Format('"%s": %s', ['nonexistent.txt', E.Message]);    // hmm...
    raise;
  end;
end;

Now, there are actually two questions:

  1. This code does compile just fine, but is it guarranteed to do so everytime, i.e., is it documented/non-undefined behavior?

  2. Is it a good practice? If not, what is the proper way to do this?

What I'm trying to do is attach the name of the file which caused the exception, without modyfing the code which raises it.

3 Replies 3

Looks just as I would have done it.

Technically, what you have will work just fine, as the caught Exception is just another object in memory, so you can freely modify it before re-raising it.

However, it is not "best practice" to modify a caught exception. A better option would be to raise a new Exception object that has your desired details in it, and the caught Exception is assigned to the new exception's InnerException property. Use the Exception.RaiseOuterException() method for this purpose, eg:

type
  ECantOpenFileException = class(Exception)
  public
    FileName: string;
    constructor Create(const AFileName: string);
  end;

constructor ECantOpenFileException.Create(const AFileName: string);
begin
  inherited Create('File "' + AFileName + '" could not be opened');
  FileName := AFileName;
end;

...

try
  // ...
  raise EFileNotFoundException.Create('File not found!');
except
  on E: Exception do begin
    Exception.RaiseOuterException(ECantOpenFileException.Create('nonexistent.txt'));
  end;
end;

If a higher exception handler wants to know why you raised an exception, they can walk the exception's InnerException chain to gather those details, eg:

try
  ...
except
  on E: Exception do
  begin
    var Msg := E.Message;
    var innerEx := E.InnerException;
    while innerEx <> nil do begin
      Msg := Msg + #10'  ' + innerEx.Message;
      innerEx := innerEx.InnerException;
    end;
    ShowMessage(Msg);
  end;
end;

@MatthiasB your proposed edit to my answer is not necessary. RaiseOuterException() is a class procedure, so it can (and should) be called on the Exception class itself, as I showed. It does not need to be called on the caught Exception object. Internally, it knows what the active Exception object is (via System.ExceptObject), and will capture it into the InnerException of the new Exception object that it is being asked to raise.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.